反射----3
反射获取构造方法
----------- android培训、java培训、java学习型技术博客、期待与您交流! ------------
1. 通过反射获取Class的构造方法
1). 通过反射获取类的默认空参构造函数
(1). Class类的newInstance()方法
newInstance( )方法的源码声明:
public T newInstance() throws InstantiationException,IllegalAccessException;
(2). 通过Class的newInstance() 方法建立类对象
【示例代码】
//1. 通过Class对象的newInstance()方法调用类的默认空参构造方法
public static void getConstructor1(){
try{
Stringname ="cn.itcast.bean.Person";
Classclazz =Class.forName(name);
Objectobj = clazz.newInstance();
}catch(ClassNotFoundException cnfe){
sop(cnfe.toString());
}catch(InstantiationException ite){
sop(ite.toString());
}catch(IllegalAccessException iae){
sop(iae.toString());
}
}
打印结果:Person run… [这个是Person类的默认构造函数]
[2]. 优势:
通过Class类对象的newInstance( )来创建Class类对象对应的类的实例好处就是:
{1}. 仅仅以字符串的形式将cn.itcast.bean.Person这个类名传递给Class的静态方法forName之后,就可以创建Person类的对象。
{2}. 应用的时候,就将“cn.itcast.bean.Person”暴露到配置文件中,非常方便。程序的可扩展性很强。
[3]. 通过Class类对象的newInstance( )方法调用的是Class类对象所属类的默认空参构造函数。
(3). Class类的newInstance()抛出的两种异常
[1]. InstantiationException
Class;类对象所属的类如果没有默认空参构造函数,但是又调用了Class类对象的newInstance( )方法的时候,会抛出java.lang.InstantiationException
【示例】
Person类:没有默认空参构造函数
package cn.itcast.bean;
public class Person {
private int age;
private String name;
public Person(String name, int age){
super();
this.age =age;
this.name =name;
System.out.println("Person param run..."+ this.name+":" + this.age);
}
}
测试类中:
String name ="cn.itcast.bean.Person";
Class clazz =Class.forName(name);
Object obj = clazz.newInstance();
抛出异常如下:
[2]. IllegalAccessException
当实体类中的默认空参构造函数的访问权限是private而不是public的时候,通过Class的newInstance( )方法会抛出异常:java.lang.IllegalAccessException
【示例代码】
Person类:Person()访问权限私有化
public class Person {
private int age;
private String name;
private Person(){
System.out.println("Person run...");
}
public Person(String name, int age){
super();
this.age =age;
this.name =name;
System.out.println("Person param run..."+ this.name+":" + this.age);
}
}
测试类:
String name ="cn.itcast.bean.Person";
Class clazz =Class.forName(name);
Object obj = clazz.newInstance();
抛出如下异常:
java.lang.IllegalAccessException: Class ReflectDemoII can not accessa member of class cn.itcast.bean.Person with modifiers "private"
2). 通过反射获取类的指定构造函数
(1). 构造函数类java.lang.reflect.Constructor
[1]. Constructor所在的位置
在java语言包的反射子包java.lang.reflect中含有反射用到的类Constructor。
[2]. Constructor类描述的事物
Constructor类抽象的是各个类的构造函数的总体。
[3]. Constructor类的源码声明
public final classConstructor<T>…{…}
【结论】Constructor是不可以被继承的泛型类
(2). 获取构造函数类Constructor对象的方式
实体类代码:
public class Student extends Person{
public Student(String name, int age){
super(name, age);
}
}
/
Class类对象有3种方法可以获取到Constructor类对象。
[1]. Class类的getConstructors()方法
public Constructor<?>[]getConstructors() throws SecurityException
{1}. 参数说明:返回值类型是构造函数对象数组Constructor<?>[]
数组中每个元素的类型是Constructor<?>,使用了泛型通配符。本以为可以返回父类构造,因为使用的是<?>。但是运行含有继承关系的类的代码没有发现有父类的构造函数输出。所以,我觉得应该是Constructor<T>
{2}. 测试代码:
Class clazz =Class.forName("cn.itcast.bean.Student");
Constructor[] cons=clazz.getConstructors();
for(Constructor con: cons){
System.out.println(con);
}
打印结果:
publiccn.itcast.bean.Student(java.lang.String,int)
[2]. Class类的getDeclaredConstructors()方法
public Constructor<?>[]getDeclaredConstructors() throws SecurityException
{1}. 参数说明:返回值类型依旧是含有通配符的构造函数类对象数组Constructor<?>[]
{2}. 测试代码:
Class clazz =Class.forName("cn.itcast.bean.Person");
Constructor[] cons=clazz.getConstructors();
Constructor[] consI=clazz.getDeclaredConstructors();
for(Constructor con: consI){
System.out.println(con);
}
打印结果:
private cn.itcast.bean.Person()
publiccn.itcast.bean.Person(java.lang.String,int)
[3]. Class类的 getConstructor(Class<?>... parameterTypes)方法
public Constructor<T> getConstructor(Class<?>...parameterTypes) throws NoSuchMethodException,SecurityException
参数说明:
{1}1. 输入参数:Class<?>... parameterTypes <===>Class<?>[]parameterTypes
使用可变参数数组原因:只有一个参数 (一定是最后一个参数) ,又是数组===>变成可变参数数组。
数组中的每个元素类型是Class<?>,原因是每一种不同类型的构造函数都有不同类型的参数。每一种参数对应自己不同的字节码文件,也就是不同的Class对象。所以Class<?>可以接受各种类对应的字节码文件。所以不用Class<T>而是用Class<?>
{1}2. 返回值类型:Constructor<T>:因为你是要返回这个Class对象所属的类的指定的Constructor,所以应该写成Constructor<T>而不是Constructor<?>
(3). 调用Constructor这个类对象的newInstance()方法来构造实例
[1]. Constructor类的newInstance( )方法的源码声明
public T newInstance(Object ... initargs)…;
[2]. 参数类型
{1}. 输入值类型:Object ... initargs ===>可变参数数组Object[]
数组中元素的类型是Object而不是T的原因是:
获取Constructor对象之后,是要向这个指定的构造函数对象中传递参数的。具体传递什么参数不知道,所以只能多态统一成Object。没有将Object升华为T的原因是,T是Constructor的类型,也就是Constructor对象所在的字节码文件中的构造函数。这个T代表对应的类的类型。这个T和newInstance中的参数类型含义不同。所以不可以。
{2}. 返回值类型T:正好是要创建实例对象的类型。
{3}. 示例代码:
//2. 通过Class对象的getConstructor()方法获取指定的参数的构造方法,之后再通过这个构造方法对象的newInstance()
//来实例化对象
public static void getConstructor2(){
try{
Stringname ="Person";
Classclazz =Class.forName(name);
Constructorconstructor = clazz.getConstructor(String.class, int.class);
Objectobj =constructor.newInstance("Benjamin", 28);
}catch(ClassNotFoundException cnfe){
sop(cnfe.toString());
}catch(InstantiationException ite){
sop(ite.toString());
}catch(IllegalAccessException iae){
sop(iae.toString());
}catch(NoSuchMethodException nse){
sop(nse.toString());
}catch(InvocationTargetException ite){
sop(ite.toString());
}
}
运行结果:Person param run...Benjamin:28
2. new创建对象 VS 反射创建对象
1). 使用反射调用默认无参构造函数创建对象
(1). 步骤
[1]. 通过Class类的方法newInstance()方法建立对象的步骤
step1:通过以字符串形式给出的全类名 ===>获取Class对象
step2:调用Class对象的newInstance()方法来实例化Class对象对应类的实例
(2). 与new创建对象的关系
【结论】无论是new建立对象还是反射建立对象,JVM执行的步骤是一样的,只不过代码的表现形式不一样。
2). 使用反射调用指定参数构造函数创建对象
(1). 步骤
通过Constructor类的方法newInstance(Object…initArgs)方法建立对象的步骤
step1:通过以字符串形式给出的全类名 ===>获取Class对象
step2:调用Class对象的getConstructor()方法来该类指定的构造函数类Constructor类的对象
step3:调用Constructor对象的newInstance(Object…initArgs)方法构建对象。
(2). 指定参数构造和使用无参构造的区别
利用反射调用指定构造函数的步骤比利用反射调用默认构造函数的步骤多一步获取Constructor的步骤,别的都一样。
----------- android培训、java培训、java学习型技术博客、期待与您交流! ------------