说起java中的反射,我们肯定都不陌生。脑海中瞬间回想起反射的一般用法:
Class cls = Class.forName("com.xxx.xxx");
Object obj = cls.newInstance();
//紧接着可以访问该类的属性或方法
...
这时如果有人问你,这不就是一个类的初始化过程吗,这和平常写的newXXX()有什么区别呢,还要写这么多代码,简直浪费我的时间%#&!)¥#*(¥。。。。
我默默点上一根烟,深深吸了一口,抬起头,45°角仰望天空,忧郁的眼神透露着看透世事的沧桑,感慨着现在的年轻人,就知道打工打工,会用会用,根本不愿意了解一些深层次一点的东西。我开口了!!!瞬间脱口而出其内部实现原理并涛涛不觉各种引经据典加以侧面论证说明他们之间的各种不同之处,侧面看去,我伟岸的身影在金色的阳光下格外耀眼,那指点江山般激昂的姿态是那么迷人。。。
“喂。。喂。。。醒醒了,你看看你,哈喇子流那么长,梦见个美女也不至于这样吧。。。该搬砖了,老板说了,今晚发版本,可能要通宵。。。”隔壁的同事阿豪拍了拍睡得正香的我。我揉了揉眼,朦胧间依稀看见个金色的身影越飞越远,大脑中好像少了些什么,我知道,那是我以前学的一些知识点,一觉醒来,又忘得一干二净。
看来!!好记性不如烂笔头!!我要记录下那些曾经我所拥有过的东西!!
A a = (A)Class.forName("pacage.A").newInstance();
A a = new A();
以上两行代码的效果其实是一样的。那它们到底有没有区别呢,肯定是有的。
它们的区别在于创建对象的方式不一样,前者是使用类加载机制,后者是创建一个新类。
那么为什么会有两种创建对象方式?这主要考虑到软件的可伸缩、可扩展和可重用等软件设计思想。
Java中工厂模式经常使用newInstance()方法来创建对象,因此从为什么要使用工厂模式上可以找到具体答案。 例如:
class c = Class.forName(“Example”);
factory = (ExampleInterface)c.newInstance();
其中ExampleInterface是Example的接口,可以写成如下形式:
String className = "Example";
class c = Class.forName(className);
factory = (ExampleInterface)c.newInstance();
进一步可以写成如下形式:
String className = readfromXMlConfig;//从xml 配置文件中获得字符串
class c = Class.forName(className);
factory = (ExampleInterface)c.newInstance();
上面代码已经不存在Example的类名称,它的优点是,无论Example类怎么变化,上述代码不变,甚至可以更换Example的兄弟类Example2 , Example3 , Example4……,只要他们继承ExampleInterface就可以。
总结
从JVM的角度看,我们使用关键字new创建一个类的时候,这个类可以没有被加载。但是使用newInstance()方法的时候,就必须保证:
- 这个类已经加载
- 这个类已经连接了
而完成上面两个步骤的正是Class的静态方法forName()所完成的,这个静态方法调用了启动类加载器,即加载java API的那个加载器。
newInstance()实际上是把new这个方式分解为两步,即首先调用Class加载方法加载某个类,然后实例化。 这样分步的好处是显而易见的。我们可以在调用class的静态加载方法forName时获得更好的灵活性,提供给了一种降耦的手段。
最后用最简单的描述来区分new关键字和newInstance()方法的区别:
newInstance: 弱类型 、低效率 、只能调用无参构造。
new: 强类型 、相对高效 、能调用任何public构造。