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

kar*_*vai 20 java reflection

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

我已经为一个简单的类运行了以下代码,该类A显示使用Class.forname("A").newInstance()比使用just的速度慢70-100倍new A().

我很想知道为什么会有这么大的时间差异,但无法弄清楚.请有人帮我理解原因.

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

use*_*421 25

A a = new A();
Run Code Online (Sandbox Code Playgroud)

直接调用new运算符和构造函数,源文本中提到的位置已经加载并初始化.AA

A a = (A) Class.forName("A").newInstance();
Run Code Online (Sandbox Code Playgroud)
  • 看看是否A已经加载
  • 如有必要,请加载它
  • 必要时初始化它
  • 通过反射找到no-args构造函数
  • new通过反射调用操作符和no-args构造函数
  • 对结果进行类型转换 A

  • 实际上你不能假设当执行`new A()`时,类'A`已经被加载并初始化了.相反,这可能恰好是"A"在第一次加载和初始化时的点,使用"A".在类加载方面,典型的JVM(包括Oracle的JVM)很懒惰. (8认同)
  • 这个[小段代码](http://ideone.com/S0jKZX)演示了Holger所说的内容:该类可以按需加载. (2认同)

alf*_*sin 5

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

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