Java实例化类详解
Java中实例化类的动作,你是否还是一成不变new对应对象呢?
经手的项目多了,代码编写量自然会增加,渐渐的会对设计模式产生感觉。
怎样使书写出来的类实例化动作,高内聚,低耦合,又兼具一定的扩展能力呢?
本文试图从几段鲜活的代码入手,给大家呈现不一样的Java实例化类。
下面代码取自com.google.zxing源码实现:
publicBitMatrixencode(Stringcontents,BarcodeFormatformat,intwidth,intheight,Map<EncodeHintType,?>hints)throwsWriterException{ Objectwriter; switch(format.ordinal()){ case1: writer=newAztecWriter(); break; case2: writer=newCodaBarWriter(); break; case3: writer=newCode39Writer(); break; case4: case10: case13: case14: default: thrownewIllegalArgumentException("Noencoderavailableforformat"+format); case5: writer=newCode128Writer(); break; case6: writer=newDataMatrixWriter(); break; case7: writer=newEAN8Writer(); break; case8: writer=newEAN13Writer(); break; case9: writer=newITFWriter(); break; case11: writer=newPDF417Writer(); break; case12: writer=newQRCodeWriter(); break; case15: writer=newUPCAWriter(); break; case16: writer=newUPCEWriter(); } return((Writer)writer).encode(contents,format,width,height,hints); }
其中的BarcodeFormat是这样的:
publicenumBarcodeFormat{ 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; privateBarcodeFormat(){ } }
源码提供的功能是将信息通过几种不同类型条形码Wirter输出为位矩阵,然后输出到图片上面,形成随处可见的各种类型的条形码。
BitMatrixbitMatrix=newMultiFormatWriter().encode(_text,BarcodeFormat.QR_CODE,qrcodeWidth,qrcodeHeight,hints);
MatrixToImageWriter.writeToFile(bitMatrix,qrcodeFormat,QrcodeFile);
源码作者在这里使用了JDK1.5 中引入的新特性enum枚举类,编写了BarcodeFormat类,其中定义了不同类型的条形码的属性。
调用MultiFormatWriter.encode() 根据入参BarcodeFormat.xx在枚举类中的序号,来实例化具体的类。
switch(format.ordinal()){ case1: writer=newAztecWriter(); break; case2: writer=newCodaBarWriter(); break; case3: writer=newCode39Writer(); break; ...............
这些条形码Writer类,同时都实现了抽象接口Writer的两个encode()方法。
publicinterfaceWriter{ BitMatrixencode(Stringvar1,BarcodeFormatvar2,intvar3,intvar4)throwsWriterException; BitMatrixencode(Stringvar1,BarcodeFormatvar2,intvar3,intvar4,Map<EncodeHintType,?>var5)throwsWriterException; }
具体的条形码Wirter类内部根据不同类型的条形码规则,进行不同的逻辑。
使用者不需要过多的关注内部的实现,需要产生什么样子的条形码,入参选用合适的条形码类型即可,笔者上述的例子里面实现的是二维码。
在来看经典MVC框架Webwork动态实例化类的一段方法代码:
privatestaticConfigurationgetDefaultConfiguration(){ if(defaultImpl==null){ defaultImpl=newDefaultConfiguration(); try{ StringclassName=getString("webwork.configuration"); if(!className.equals(defaultImpl.getClass().getName())){ try{ defaultImpl=(Configuration)ObjectFactory.getObjectFactory().buildBean(Thread.currentThread().getContextClassLoader().loadClass(className)); }catch(Exceptione){ LOG.error("Couldnotinstantiateconfiguration",e); } } returndefaultImpl; }catch(IllegalArgumentExceptionlocalIllegalArgumentException){ } } }
源码取自webwork-core,可能很多看客老爷没有听闻Webwork,但是对Struts应该是如雷贯耳,Struts2核心改写自Webwork。
上述源码提供的功能为实例化用户自己定义的配置文件读取类,该定义是在配置文件当中。
源码作者在这里使用Thread.currentThread().getContextClassLoader().loadClass(className)线程中类加载器,动态实例化自定义配置文件读取类,可谓是效率最高的一种做法。
类加载器的委托链:SystemClassloader->ExtensionClassloader->BootstrapClassloader
委派链左边的ClassLoader就可以很自然的使用右边的ClassLoader所加载的类,类加载的机制为判断自已是否加载该类,没有在询问上级。
而这三个类加载器分别对应着编译器去寻找类文件的优先级别和不同的路径:
- BootClassLoader 它是用C++编写的,从%jre%/lib目录中加载类,或者运行时用-Xbootclasspath指定目录来加载。是编译器最优先寻找class的地方
- ExtClassLoader 从%jre%/lib/ext目录加载类,或者运行时用-Djava.ext.dirs制定目录来加载。是编译器次优先寻找class的地方
- SystemClassloader也就是我们常说的AppClassloader,它对应当前路径,所以也是编译器默认找class的地方。
平时项目中使用的Class.forname()会从BootstrapClassloader开始询问,是最消耗资源的。
源码作者在这里采用线程类加载器,对应为SystemClassloader,效率无疑是最高的。