Class.newInstance()与new、Constructor.newInstance()的区别

本文探讨了newInstance()与new关键字在Java中的不同之处,包括它们在创建对象时的工作原理、使用场景及灵活性。newInstance()适用于运行时配置,而new更注重类型安全性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在初始化一个类,生成一个实例的时候,newInstance() 和 new 有什么区别?

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


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


  进一步,如果下面写,你可能会理解:
  1. String className = readfromXMlConfig;  
  2. //从xml 配置文件中获得字符串  
  3. Class c = Class.forName(className);  
  4. 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的加载方法加载某个类,然后实例化。
  这样分步的好处是显而易见的。new者,包括用A.class,在编译期已经确定,不可能在运行期变更,一旦要变更必须改变这部分代码,而newInstance者,Class.forName(String)的参数可以在运行期配置,而无须改动代码, 我们可以在调用class的静态加载方法forName时获得更好的灵活性,提供给了我们降耦的手段。

newInstance: 弱类型。低效率。 只能调用无参构造

new: 强类型。相对高效。能调用任何public构造。

newInstance() 的参数版本与无参数版本详解

通过反射创建新的类示例,有两种方式:

Class.newInstance()

Constructor.newInstance()


以下对两种调用方式给以比较说明:
Class.newInstance() 只能够调用 无参的构造函数,即默认的构造函数;
Constructor.newInstance() 可以根据传入的参数,调用 任意构造构造函数。

Class.newInstance() 抛出所有由被调用构造函数抛出的异常。

Class.newInstance() 要求被调用的构造函数是可见的,也即必须是 public类型的;
Constructor.newInstance() 在特定的情况下,可以 调用私有的构造函数。

Class A(被调用的示例):
  1. public class A {  
  2.     private A() {  
  3.         System.out.println("A's constructor is called.");  
  4.     }  
  5.   
  6.     private A(int a, int b) {  
  7.         System.out.println("a:" + a + " b:" + b);  
  8.     }  
  9. }  

Class B(调用者):
  1. public class B {   
  2.     public static void main(String[] args) {   
  3.         B b=new B();   
  4.         out.println("通过Class.NewInstance()调用私有构造函数:");   
  5.         b.newInstanceByClassNewInstance();   
  6.         out.println("通过Constructor.newInstance()调用私有构造函数:");   
  7.         b.newInstanceByConstructorNewInstance();   
  8.     }   
  9.     /*通过Class.NewInstance()创建新的类示例*/   
  10.     private void newInstanceByClassNewInstance(){   
  11.         try {/*当前包名为reflect,必须使用全路径*/   
  12.             A a=(A)Class.forName("reflect.A").newInstance();   
  13.         } catch (Exception e) {   
  14.             out.println("通过Class.NewInstance()调用私有构造函数【失败】");   
  15.         }  
  16.     }  
  17.       
  18.     /*通过Constructor.newInstance()创建新的类示例*/   
  19.     private void newInstanceByConstructorNewInstance(){   
  20.         try {/*可以使用相对路径,同一个包中可以不用带包路径*/   
  21.             Class c=Class.forName("A");   
  22.             /*以下调用无参的、私有构造函数*/   
  23.             Constructor c0=c.getDeclaredConstructor();   
  24.             c0.setAccessible(true);   
  25.             A a0=(A)c0.newInstance();   
  26.             /*以下调用带参的、私有构造函数*/   
  27.             Constructor c1=c.getDeclaredConstructor(new Class[]{int.class,int.class});   
  28.             c1.setAccessible(true);   
  29.             A a1=(A)c1.newInstance(new Object[]{5,6});   
  30.         } catch (Exception e) {   
  31.             e.printStackTrace();   
  32.         }   
  33.     }   
  34. }  

输入结果如下:
通过Class.NewInstance()调用私有构造函数:
通过Class.NewInstance()调用私有构造函数【失败】
通过Constructor.newInstance()调用私有构造函数:
A's constructor is called.
a:5 b:6

说明方法newInstanceByClassNewInstance调用失败,而方法newInstanceByConstructorNewInstance则调用成功。
如果被调用的类的构造函数为默认的构造函数,采用Class.newInstance()则是比较好的选择,
一句代码就OK;如果需要调用类的带参构造函数、私有构造函数,
就需要采用Constractor.newInstance(),两种情况视使用情况而定。
不过Java Totorial中推荐采用Constractor.newInstance()。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值