本文转载自
https://blog.csdn.net/panda1234lee/article/details/9009719
https://blog.csdn.net/qq_29631069/article/details/79177543
用newInstance与用new是区别的,区别在于创建对象的方式不一样,前者是使用类加载机制,那么为什么会有两种创建对象方式?这个就要从可伸缩、可扩展,可重用等软件思想上解释了。
从jvm的角度看,我们使用new的时候,这个要new的类可以没有加载; 但是使用newInstance时候,就必须保证:
1、这个类已经加载;
2、这个类已经连接了。
而完成上面两个步骤的正是class的静态方法forName方法,这个静态方法调用了启动类加载器(就是加载java API的那个加载器)。有了上面jvm上的理解,那么我们可以这样说,newInstance实际上是把new这个方式分解为两步,即,首先调用class的加载方法加载某个类,然后实例化。
这样分步的好处是显而易见的。new者,包括用A.class,在编译期已经确定,不可能在运行期变更,一旦要变更必须改变这部分代码,而newInstance者,Class.forName(String)的参数可以在运行期配置,而无须改动代码,我们可以在调用class的静态加载方法forName时获得更好的灵活性,提供给了我们降耦的手段。
通过反射创建新的类示例,有两种方式:
Constructor.newInstance()
其中
Class.newInstance() 只能够调用无参的构造函数,即默认的构造函数;
Constructor.newInstance() 可以根据传入的参数,调用任意构造构造函数。
Class.newInstance() 抛出所有由被调用构造函数抛出的异常。
Class.newInstance() 要求被调用的构造函数是可见的,也即必须是public类型的;
Constructor.newInstance() 在特定的情况下,可以调用私有的构造函数。
举例:
public class Demo {
public static void main(String[] args) {
try {
/**
* Class.forName(String):要求JVM查找并加载String指定的类
* 返回String串指定的类
*/
Class clazz = Class.forName("com.yao.test.sjmstest.Demo");
Demo demo = (Demo) clazz.newInstance();
demo.method(demo);
//new方式
Demo demo1 = new Demo();
demo1.method(demo1);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
public void method(Demo demo) {
System.out.println(demo);
}
}
运行结果:
com.yao.test.sjmstest.Demo@1d44bcfa
com.yao.test.sjmstest.Demo@266474c2
可见两种方法得到的对象并没有什么区别
实际应用
接口:
public interface ParentPrint {
void print(String classname);
}
子类A:
public class A implements ParentPrint{
public void print(String classname) {
System.out.println("Clas A");
System.out.println(classname);
}
}
子类B:
public class B implements ParentPrint {
public void print(String classname) {
System.out.println("Class B");
System.out.println(classname);
}
}
工厂类:
public class PrintFactory {
public static ParentPrint getParentPrint(Class clazz) {
try {
ParentPrint print = (ParentPrint) clazz.newInstance();
return print;
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return null;
}
}
测试类:
public class Main {
public static void main(String[] args) {
ParentPrint print = PrintFactory.getParentPrint(A.class);
print.print("A");
ParentPrint print1 = PrintFactory.getParentPrint(B.class);
print.print("B");
}
}
运行结果:
Clas A
A
Clas A
B