反射扩展:newInstance与new之间的比较与讨论

newInstance: 弱类型。低效率。只能调用无参构造。
new: 强类型。相对高效。能调用任何public构造。
newInstance()是实现IOC、反射、面对接口编程 和 依赖倒置 等技术方法的必然选择,new 只能实现具体类的实例化,不适合于接口编程。
里面就是通过这个类的默认构造函数构建了一个对象,如果没有默认构造函数就抛出InstantiationException, 如果没有访问默认构造函数的权限就抛出IllegalAccessException

 

 

在初始化一个类,生成一个实例的时候;newInstance() 和 new 有什么区别?
  用newInstance与用new是区别的,区别在于创建对象的方式不一样,前者是使用类加载机制,那么为什么会有两种创建对象方式?这个就要从可伸缩、可扩展,可重用等软件思想上解释了。
  Java中工厂模式经常使用newInstance来创建对象,因此从为什么要使用工厂模式上也可以找到具体答案。
  例如:
  Class c = Class.forName(“A”);

      factory = (AInterface)c.newInstance();
  其中AInterface是A的接口,如果下面这样写,你可能会理解:
  String className = "A";

      Class c = Class.forName(className);

      factory = (AInterface)c.newInstance();
  进一步,如果下面写,你可能会理解:
  String className = readfromXMlConfig;//从xml 配置文件中获得字符串

      Class c = Class.forName(className);

      factory = (AInterface)c.newInstance();
  上面代码就消灭了A类名称,优点:无论A类怎么变化,上述代码不变,甚至可以更换A的兄弟类B , C , D....等,只要他们继承Ainterface就可以。
   从jvm的角度看,我们使用new的时候,这个要new的类可以没有加载;
  但是使用newInstance时候,就必须保证:1、这个类已经加载;2、这个类已经连接了。而完成上面两个步骤的正是class的静态方法forName()方法,这个静态方法调用了启动类加载器(就是加载java API的那个加载器)。
  有了上面jvm上的理解,那么我们可以这样说,newInstance实际上是把new这个方式分解为两步,即,首先调用class的加载方法加载某个类,然后实例化。

 

  这样分步的好处是显而易见的。我们可以在调用class的静态加载方法forName时获得更好的灵活性,提供给了我们降耦的手段。

 

关于newInstance降耦的讨论见如下(非本人观点,仅供参考):

 

newInstance 不过就是能做动态生成而已。这是reflection的功能,也是唯一的功能。

假如new也可以动态,就没什么区别了,如:new "MyClass"。

我发现不知道为什么,很多人认为reflection可以减少耦合。可能都是指的可以在配置文件里面配置类名字吧。

这在客观上确实达到了降低耦合的目的,但是,实际上,我要说,此处降低耦合的不是reflection,而是那个你cast过去的interface。interface,只有interface,才是推动历史的唯一力量。 :->

reflection不过提供了把实现的决定时间延迟到运行时的功能而已。


而其实,即使使用reflection,也应该把它包装在一个抽象工厂中,如此才能隐藏reflection的缺点。而且,抽象工厂可以表达reflection,而reflection不能表达抽象工厂。

举个例子:

不要直接在客户代码中这样写:
MyInterface obj = (MyInterface)Class.forName(theclassname).newInstance();
如此,你就把自己强制绑在reflection上,这也是强耦合的一种。

而是利用抽象工厂:
interface MyInterfaceFactory{
MyInterface newInstance();
}
class ClientCode{
private final MyInterfaceFactory myfactory;
public void f(){
MyInterface obj = myfactory.newInstance();
}
}

这个myfactory是一个抽象工厂对象,它可以通过构造函数注射进来。

然后,可以提供一个使用reflection的工厂实现

class ReflectionFactory implements MyInterfaceFactory{
public MyInterface newInstance(){
return Class.forName(name).newInstance();
}
private final String name;
}
这样,reflection也好,newInstance也好,都是一个工厂实现而已,不会影响整个框架。
这才是低耦合。

 

懒得长篇大论,随便拿jive举个例子,ForumFactory中的:
String classNameProp = JiveGlobals.getJiveProperty("ForumFactory.className");
Class c = Class.forName(className);
factory = (ForumFactory)c.newInstance();

如果改用new DbForumFactory()那就完蛋了,难道每个想修改jive实现的人都要去反编译再重写ForumFactory?

 

呵呵。你这个例子,真正起到消除耦合的,正是这个ForumFactory接口,而不是reflection。

不信,可不可以这样?

ForumFactory factory = Factories.getForumFactory();

不行吗?把用reflection的逻辑封装进getForumFactory()不好吗?不比直接使用它灵活?

在getForumFactory()里面,你愿意用reflection也好,或者用其它间接层也好,都是实现细节了。而实现细节是不会影响耦合度的。

我们讨论的是框架,是设计,是分工,不是最终完成的功能。你的反问好像是说:我的功能要求动态生成,我能不用reflection吗?

当然要用,没人不让你用reflection,不过,只有在必须用的时候(在你这个必须动态生成的例子)才用,因为reflection有缺点。

其实,就算用reflection,也有各种用法,你是class.newInstance()?还是在class里面先找到某个构造函数然后调用那个构造函数?还是说再委托给第三方的如spring啦,pico啦来创建对象?(这些库底层也是调用reflection的)

你能说你的newInstance()就是千秋万载永远正确的选择?

而把这些细节封装起来,才能达到减小耦合的效果。

一个检测的办法就是:你试着改变策略,用pico或者直接new,看看要改动的代码有多少。

 

好像已经偏离了讨论的意图,讨论的是newInstance和new的区别,而不是>在问工厂模式、类与类之间的耦合之类的东西;

是的,从表面上看好像是偏离,产生这个疑问在于自己还没有对设计模式 或有关Java设计理论有所了解,在工厂模式中,就常常使用newIntance来创建对象,而不是使用new,如下:

 Class c = Class.forName(className);
 factory = (ForumFactory)c.newInstance();

很多初学者奇怪:为什么这里不直接使用new?用newInstance与用new是区别的,区别在哪里?就在于为什么要使用工厂模式的答案中。

 

wInstance与用new是区别的,区别在于创建对象的方式不一样,前者是使用类加载机制,那么为什么会有两种创建对象方式?这个就要从可伸缩、可扩展,可重用等软件思想上解释了。

Java中工厂模式经常使用newInstance来创建对象,因此从为什么要使用工厂模式上也可以找到具体答案。

例如:


Class c = Class.forName(“A”);
factory = (AInterface)c.newInstance();

其中AInterface是A的接口,如果下面这样写,你可能会理解:

String className = "A" ;
Class c = Class.forName(className);
factory = (AInterface)c.newInstance();


进一步,如果下面写,你可能会理解:


String className = readfromXMlConfig;//从xml 配置文件中获得字符串
Class c = Class.forName(className);
factory = (AInterface)c.newInstance();


上面代码就消灭了A类名称,优点:无论A类怎么变化,上述代码不变,甚至可以更换A的兄弟类B , C , D....等,只要他们继承Ainterface就可以。

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值