Java 调用类构造函数和使用class.forName().newInstance之间的区别

Java 调用类构造函数和使用class.forName().newInstance之间的区别,java,reflection,Java,Reflection,我一直在试图理解使用new实例化对象与使用Class.forName(“A”).newInstance()实例化对象之间的区别 我为一个简单的类a运行了以下代码,其中显示了使用class.forname(“a”).newInstance()比仅使用newa()慢70-100倍 我很想知道为什么时间上会有如此大的差异,但我不明白。请有人帮我理解原因 public class Main4test { public Main4test() { } static int tu

我一直在试图理解使用
new
实例化对象与使用
Class.forName(“A”).newInstance()实例化对象之间的区别

我为一个简单的类
a
运行了以下代码,其中显示了使用
class.forname(“a”).newInstance()
比仅使用
newa()
慢70-100倍

我很想知道为什么时间上会有如此大的差异,但我不明白。请有人帮我理解原因

public class Main4test {

    public Main4test() {
    }

    static int turns = 9999999;

    public static void main(String[] args) {
        new Main4test().run();
    }

    public void run() {
        System.out.println("method1: " + method1() + "");
        System.out.println("method2:" + method2() + "");
    }

    public long method2() {
        long t = System.currentTimeMillis();
        for (int i = 0; i < turns; i++) {
            try {
                A a = (A) Class.forName("A").newInstance();
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        }
        return System.currentTimeMillis() - t;
    }

    public long method1() {
        long t = System.currentTimeMillis();
        for (int i = 0; i < turns; i++) {
            try {
                A a = new A();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return System.currentTimeMillis() - t;
    }

}

public class A {
    int a;
    public A() {
    a=0;
    }
}
公共类Main4test{
公共维护测试(){
}
静态整数圈数=9999999;
公共静态void main(字符串[]args){
新建Main4test().run();
}
公开募捐{
System.out.println(“method1:+method1()+”);
System.out.println(“method2:+method2()+”);
}
公共长方法2(){
long t=System.currentTimeMillis();
对于(int i=0;i
直接调用
new
运算符和
A
的构造函数,其中
A
在源文本中提到,因此已加载并初始化

A a = (A) Class.forName("A").newInstance();
  • 查看是否已加载
    A
  • 如有必要,将其加载
  • 如有必要,初始化它
  • 通过反射找到无参数构造函数
  • 通过反射调用
    new
    操作符和no-args构造函数
  • 将结果键入
    A

使用反射
Class.forName(“A”).newInstance()
不仅是一个代价高昂的操作(因为需要在运行时将正确的类加载器委托给类并加载该类),而且会使代码更难调试,并且会失去类型安全的所有优势(在编译期间发生)

结论:

避免反射,除非您必须使用它(例如,如果您正在编写面向方面的插件/库)

用于测量速度的测试不是有效的测试。Java性能非常复杂,它首先涉及热点vm、智能编译器和垃圾收集器

在方法1中,java通常足够聪明,只在内存中创建一个实例,并在每次迭代中重用它

在方法2中,您强制VM使用反射和类加载器来生成对象。
这本身就已经慢了

传统的
new
newInstance
之间的主要区别在于,newInstance允许灵活地实例化运行时才知道的类,并使代码更具动态性。如果直到运行时才知道该类,则应该使用反射

从中,调用
Class.forName(String)
返回与具有给定字符串名称的类或接口关联的类对象,即返回类A

因此
A=(A)Class.forName(“A”).newInstance()
分解为:

  • Class.forName(“A”)

    返回类的类型A

  • Class.forName(“A”).newInstance()
    创建由该类对象表示的类的新实例,从而获得类型a的实例。该类被实例化,就好像是由一个带有空参数列表的新表达式实例化一样。如果尚未初始化该类,则初始化该类。这实际上相当于一个新的a(),它返回a的一个新实例。

    重要提示:使用此方法可以有效地绕过编译器执行的编译时异常检查

参考:

下面列出了
new
操作符和
newInstance
方法之间的区别:

  • 通过传递构造函数接受的任意数量的参数,new运算符可以与类的任何构造函数一起使用。 newInstance方法要求在为其调用的类中不存在任何参数构造函数。如果要将构造函数与newInstance一起使用,则需要为任何构造函数获取构造函数类的实例,然后调用newInstance,如:

    Class class = Class.forName("A");  
    Constructor const = class.getConstructor(A.class);  
    A a = null;  
    const.newInstance(a);
  • 使用new操作符不需要显式加载类,因为它是由JVM在内部处理的。 对于newInstance()方法,该类的类对象的实例是必需的(class.forName(“A”).newInstance();或如上所示)。引用基础类的类对象是通过调用forName方法获得的

  • 当类的名称在编译时已知时,建议使用new运算符。 由于newInstance使用反射来创建类的对象,因此建议在编译时不知道该类,但在运行时确定该类时使用

  • 由于并没有像new操作符中的forName这样的与方法调用相关的额外处理,所以它比newInstance更快。 使用newInstance会导致JVM部分的额外处理(类型检查、安全检查),因此不建议将其用于per
    Class class = Class.forName("A");  
    Constructor const = class.getConstructor(A.class);  
    A a = null;  
    const.newInstance(a);