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-06Java方法調(diào)用解析靜態(tài)分派動(dòng)態(tài)分派執(zhí)行過程
這篇文章主要為大家介紹了Java方法調(diào)用解析靜態(tài)分派動(dòng)態(tài)分派執(zhí)行過程,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-06-06Java兩個(gè)變量的互換(不借助第3個(gè)變量)具體實(shí)現(xiàn)方法
這篇文章主要介紹了Java兩個(gè)變量的互換(不借助第3個(gè)變量)具體實(shí)現(xiàn)方法,需要的朋友可以參考下2014-02-02java swing實(shí)現(xiàn)簡(jiǎn)單計(jì)算器界面
這篇文章主要為大家詳細(xì)介紹了java swing實(shí)現(xiàn)簡(jiǎn)單計(jì)算器界面,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-04-04Java Kafka 消費(fèi)積壓監(jiān)控的示例代碼
這篇文章主要介紹了Java Kafka 消費(fèi)積壓監(jiān)控,本文通過示例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-07-07Java循環(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