Java實(shí)例化類詳解
Java 中實(shí)例化類的動(dòng)作,你是否還是一成不變 new 對(duì)應(yīng)對(duì)象呢?
經(jīng)手的項(xiàng)目多了,代碼編寫量自然會(huì)增加,漸漸的會(huì)對(duì)設(shè)計(jì)模式產(chǎn)生感覺。
怎樣使書寫出來的類實(shí)例化動(dòng)作,高內(nèi)聚,低耦合,又兼具一定的擴(kuò)展能力呢?
本文試圖從幾段鮮活的代碼入手,給大家呈現(xiàn)不一樣的 Java 實(shí)例化類。
下面代碼取自 com.google.zxing 源碼實(shí)現(xiàn):
public BitMatrix encode(String contents, BarcodeFormat format, int width, int height, Map<EncodeHintType, ?> hints) throws WriterException {
Object writer;
switch(format.ordinal()) {
case 1:
writer = new AztecWriter();
break;
case 2:
writer = new CodaBarWriter();
break;
case 3:
writer = new Code39Writer();
break;
case 4:
case 10:
case 13:
case 14:
default:
throw new IllegalArgumentException("No encoder available for format " + format);
case 5:
writer = new Code128Writer();
break;
case 6:
writer = new DataMatrixWriter();
break;
case 7:
writer = new EAN8Writer();
break;
case 8:
writer = new EAN13Writer();
break;
case 9:
writer = new ITFWriter();
break;
case 11:
writer = new PDF417Writer();
break;
case 12:
writer = new QRCodeWriter();
break;
case 15:
writer = new UPCAWriter();
break;
case 16:
writer = new UPCEWriter();
}
return ((Writer)writer).encode(contents, format, width, height, hints);
}
其中的 BarcodeFormat 是這樣的:
public enum BarcodeFormat {
AZTEC,
CODABAR,
CODE_39,
CODE_93,
CODE_128,
DATA_MATRIX,
EAN_8,
EAN_13,
ITF,
MAXICODE,
PDF_417,
QR_CODE,
RSS_14,
RSS_EXPANDED,
UPC_A,
UPC_E,
UPC_EAN_EXTENSION;
private BarcodeFormat() {
}
}
源碼提供的功能是將信息通過幾種不同類型條形碼 Wirter 輸出為位矩陣,然后輸出到圖片上面,形成隨處可見的各種類型的條形碼。
BitMatrix bitMatrix = new MultiFormatWriter().encode(_text, BarcodeFormat.QR_CODE, qrcodeWidth, qrcodeHeight, hints);
MatrixToImageWriter.writeToFile(bitMatrix, qrcodeFormat, QrcodeFile);
源碼作者在這里使用了JDK 1.5 中引入的新特性 enum 枚舉類,編寫了BarcodeFormat類,其中定義了不同類型的條形碼的屬性。
調(diào)用 MultiFormatWriter.encode() 根據(jù)入?yún)?BarcodeFormat.xx 在枚舉類中的序號(hào),來實(shí)例化具體的類。
switch(format.ordinal()) {
case 1:
writer = new AztecWriter();
break;
case 2:
writer = new CodaBarWriter();
break;
case 3:
writer = new Code39Writer();
break;
...............
這些條形碼 Writer 類,同時(shí)都實(shí)現(xiàn)了抽象接口 Writer 的 兩個(gè)encode()方法。
public interface Writer {
BitMatrix encode(String var1, BarcodeFormat var2, int var3, int var4) throws WriterException;
BitMatrix encode(String var1, BarcodeFormat var2, int var3, int var4, Map<EncodeHintType, ?> var5) throws WriterException;
}
具體的條形碼 Wirter 類內(nèi)部根據(jù)不同類型的條形碼規(guī)則,進(jìn)行不同的邏輯。
使用者不需要過多的關(guān)注內(nèi)部的實(shí)現(xiàn),需要產(chǎn)生什么樣子的條形碼,入?yún)⑦x用合適的條形碼類型即可,筆者上述的例子里面實(shí)現(xiàn)的是二維碼。
在來看經(jīng)典 MVC 框架 Webwork 動(dòng)態(tài)實(shí)例化類的一段方法代碼:
private static Configuration getDefaultConfiguration () {
if (defaultImpl == null) {
defaultImpl = new DefaultConfiguration();
try {
String className = getString("webwork.configuration");
if (!className.equals(defaultImpl.getClass().getName())) {
try {
defaultImpl = (Configuration) ObjectFactory.getObjectFactory().buildBean(Thread.currentThread().getContextClassLoader().loadClass(className));
} catch (Exception e) {
LOG.error("Could not instantiate configuration", e);
}
}
return defaultImpl;
} catch (IllegalArgumentException localIllegalArgumentException) {
}
}
}
源碼取自 webwork-core,可能很多看客老爺沒有聽聞 Webwork, 但是對(duì) Struts 應(yīng)該是如雷貫耳,Struts2 核心改寫自 Webwork。
上述源碼提供的功能為實(shí)例化用戶自己定義的 配置文件讀取類,該定義是在配置文件當(dāng)中。
源碼作者在這里使用 Thread.currentThread().getContextClassLoader().loadClass(className) 線程中類加載器,動(dòng)態(tài)實(shí)例化自定義配置文件讀取類,可謂是效率最高的一種做法。
類加載器的委托鏈:SystemClassloader -> ExtensionClassloader -> BootstrapClassloader
委派鏈左邊的ClassLoader就可以很自然的使用右邊的ClassLoader所加載的類,類加載的機(jī)制為判斷自已是否加載該類,沒有在詢問上級(jí)。
而這三個(gè)類加載器分別對(duì)應(yīng)著編譯器去尋找類文件的優(yōu)先級(jí)別和不同的路徑:
- BootClassLoader 它是用C++編寫的,從%jre%/lib目錄中加載類,或者運(yùn)行時(shí)用-Xbootclasspath指定目錄來加載。是編譯器最優(yōu)先尋找class的地方
- ExtClassLoader 從%jre%/lib/ext目錄加載類,或者運(yùn)行時(shí)用-Djava.ext.dirs制定目錄來加載。是編譯器次優(yōu)先尋找class的地方
- SystemClassloader 也就是我們常說的AppClassloader ,它對(duì)應(yīng)當(dāng)前路徑,所以也是編譯器默認(rèn)找class的地方。
平時(shí)項(xiàng)目中使用的 Class.forname() 會(huì)從 BootstrapClassloader 開始詢問,是最消耗資源的。
源碼作者在這里采用線程類加載器,對(duì)應(yīng)為 SystemClassloader ,效率無疑是最高的。
相關(guān)文章
數(shù)組重排序(如何將所有奇數(shù)都放在所有偶數(shù)前面)的深入分析
本篇文章是對(duì)數(shù)組重排序(如何將所有奇數(shù)都放在所有偶數(shù)前面)的方法進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-06-06
Java方法調(diào)用解析靜態(tài)分派動(dòng)態(tài)分派執(zhí)行過程
這篇文章主要為大家介紹了Java方法調(diào)用解析靜態(tài)分派動(dòng)態(tài)分派執(zhí)行過程,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-06-06
Java兩個(gè)變量的互換(不借助第3個(gè)變量)具體實(shí)現(xiàn)方法
這篇文章主要介紹了Java兩個(gè)變量的互換(不借助第3個(gè)變量)具體實(shí)現(xiàn)方法,需要的朋友可以參考下2014-02-02
java swing實(shí)現(xiàn)簡(jiǎn)單計(jì)算器界面
這篇文章主要為大家詳細(xì)介紹了java swing實(shí)現(xiàn)簡(jiǎn)單計(jì)算器界面,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-04-04
Java Kafka 消費(fèi)積壓監(jiān)控的示例代碼
這篇文章主要介紹了Java Kafka 消費(fèi)積壓監(jiān)控,本文通過示例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-07-07
Java循環(huán)結(jié)構(gòu)之多重循環(huán)及continue?break
這篇文章主要介紹了Java循環(huán)結(jié)構(gòu)之多重循環(huán)及continue?break,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的朋友可以參考一下2022-09-09

