不是通过new 构造器的方式,而是用反射的方式创建
通过反射创建对应的运行时类的对象:对应的是哪个运行时类,只能创建这个类的对象
newInstance(),调用此方法创建运行时类的对象
这个方法中实际上还是调用的是类的构造器
Object obj = clazz.newInstance();内部调用了Person类(运行时类)的空参构造器
证明方法很简单,在Person的空参构造器中加一条输出语句
执行之后如果控制台出现了输出语句,则说明调用了空参构造器
如果没有空参构造器就会报这个异常InstantiationException
IllegalAccessException表示非法访问,如果Person的空参构造器权限是私有的,就会报这个异常
要想此方法正常的创建运行时类的对象:要求
1.运行时类必须提供空参构造器
2.空参构造器的访问权限要满足要求
比如默认权限是在包内进行访问。通常设置为public
这也是javabean中要要求提供空参的权限为public的构造器的原因,反射有可能用到,便于通过反射创建运行时类的对象
还有一个原因是子类中的构造器如果没有显式的写super,相当于就是super()
如果不提供父类的空参构造器,这里就会报错
造对象都是用构造器去造的,也只有构造器才能够造对象,只是形式上有所区别
@Test
public void test() throws IllegalAccessException, InstantiationException {
Class clazz=Person.class;
Object obj = clazz.newInstance();//这个对象其实就是造的Person类的对象
System.out.println(obj);//Person{name='null', age=0}
//所以可以进行强制转换
Person p=(Person)obj;
//也可以用泛型,Class<Person> clazz=Person.class;//newInstance()返回值会自动识别为Person
}
当然也可以调用指定的某个构造器;但是这种方式用的很少,用的比较多的还是直接newInstance(),再去操作属性
Constructor cons = clazz.getConstructor(String.class, int.class);//得到指定的构造器
反射的动态性:在运行代码时可以根据某些条件改变自身结构,比如说想创哪个类的对象,在编译时是定不下来的
如果是new构造器那对象就定下来了,所以必须通过反射的方式去写
所以框架中用到反射也是利用了反射的动态性
体会反射的动态性:
//forName(String classPath);创建一个指定类的对象
//classPath为指定类的全名
public Object getInstance(String classPath) throws Exception {
Class clazz = Class.forName(classPath);//得到Class实例
return clazz.newInstance();//创建classPath所对应的类的实例
}
@Test
public void test2(){
int i = new Random().nextInt(3);//产生随机数,0,1,2中的任何一个
String classPath ="";//不要写成 String classPath ;否则下面getInstance(classPath);报错,要进行初始化
switch(i){
case 0:
classPath="java.util.Date";
break;
case 1:
//classPath="java.sql.Date";不能用这个,没有空参构造器
classPath="java.lang.Object";
break;
case 2:
classPath="test.test01";//右键类名,点击copy reference,再ctrl+v
}
try {
Object obj = getInstance(classPath);//编译完之后,并不能确定造哪个类的对象,是由运行后生成的随机数决定的
System.out.println(obj);
} catch (Exception e) {
e.printStackTrace();
}
}