目录
反射的核心类
- Class类
- Constructor构造方法类
- Method方法类
- Field成员变量类
Class类
- Class是JVM中代表“类和接口”的类
- Class对象具体包含了某个特定类的结构信息
- 通过Class对象可获取对应类的构造方法/方法/成员变量
Class核心方法
- Class.forName():静态方法,用于获取指定Class对象
- classObj.newInstance():通过默认构造方法创建新的对象
- classObj.getConstructor():获得指定的public修饰构造方法Constructor对象
- classObj.getMethod():获取指定的public修饰方法Method对象
- classObj.getField():获取指定的public修饰成员变量Field对象。
1.通过Class.forName()方法将指定的类加载到jvm(可以给指定类加静态代码块来看效果,静态块随着类的加载而加载),并返回对应Class对象,如下例的employeeClass
2.通过Class的对象的newInstance方法调用指定类的默认构造函数进行实例化,返回一个Object类的对象,需要强转成指定类
Class employeeClass = Class.forName("com.imooc.reflect.entity.Employee");
System.out.println("Employee已被加载到jvm");
//通过类对象调用newInstance方法,再通过默认构造方法创建新的对象,返回的是Object,需要强转
Employee emp = (Employee)employeeClass.newInstance();
System.out.println(emp);
Constructor构造方法类
- Constructor类是对Java类中的构造方法的抽象
- Constructor对象包含了具体类的某个具体构造方法的声明
- 通过Constructor对象调用代参构造方法创建对象
Constructor类的核心方法
- classObj.getConstructor():获取指定public修饰的构造方法对象
- ConstructorObj.newInstance():通过对应的构造方法创建对象。classObj.newInstance()是调用默认构造方法创建对象,带参的还是得通过ConstructorObj.newInstance()创建。
1.通过Class.forName()方法将指定的类加载到jvm,并返回对应Class对象,如下例的employeeClass
2.通过Class类的对象调用getConstructor方法,获得指定的public修饰构造方法Constructor对象(需要通过Class数组描述想要调用的带参构造方法的参数类型,顺序要能与带参构造方法对上)。
3.通过Constructor对象的newInstance方法调用指定类的带参构造函数进行实例化,需要给出对应构造方法的实参。
Class employeeClass = Class.forName("com.imooc.reflect.entity.Employee");
// 调用带参构造方法,但是带参构造方法可能不止一个,需要通过Class数组,描述参数的数量及对应的类型
// 得到指定格式的带参构造
Constructor constructor= employeeClass.getConstructor(new Class[]{
//对于已有的类来说已被加载,自然可以通过.class属性得到对应的类对象
Integer.class, String.class, Float.class, String.class
});
// 通过Constructor对象的newInstance方法,调用包含4个参数的构造方法实例化对象
Employee employee = (Employee)constructor.newInstance(new Object[]{
100, "李东", 3000f, "研发部"
});
System.out.println(employee);
Method方法
- Method对象指代某个类中的方法的描述
- Method对象使用classObj.getMethod()方法获取
- 通过Method对象调用指定对象的对应方法
Method类核心方法
- classObj.getMethod():获取指定public修饰的方法对象
- methodObj.invoke():调用指定对象的对应方法
1.通过Class.forName()方法将指定的类加载到jvm,并返回对应Class对象,如下例的employeeClass
2.通过Class类的对象调用getConstructor方法,获得指定的public修饰构造方法Constructor对象。
3.通过Constructor对象的newInstance方法调用指定类的带参构造函数进行实例化。
4.通过Class类的对象调用getMethod方法获取指定public修饰的方法对象,需要给出两类参数,第一个参数是指定方法的名字,以字符串形式给出,以及一个Object数组,里面给出与指定方法对应的参数的类型
5.通过Method的对象,调用invoke方法,即调用指定对象的对应方法,需要给出两类参数:相关类的对象,Object数组,里面是该对象的指定方法的实参。
Class employeeClass= Class.forName("com.imooc.reflect.entity.Employee");
Constructor constructor = employeeClass.getConstructor(new Class[]{
Integer.class, String.class, Float.class, String.class
});
Employee emp = (Employee)constructor.newInstance(new Object[]{
100, "李东", 9000.0f, "研发部"
});
System.out.println(emp);
//通过Class类的对象调用getMethod方法获取指定public修饰的方法对象,需要给出两类参数,
// 第一个参数是指定方法的名字,以字符串形式给出,以及一个Object数组,
// 里面给出与指定方法对应的参数的类型
Method updateSalaryMethod = employeeClass.getMethod("updateSalary", new Class[]{Float.class});
// 通过Method的对象,调用invoke方法,即调用指定对象的对应方法,
// 需要给出两类参数:相关类的对象,Object数组,里面是该对象的指定方法的实参。
emp = (Employee) updateSalaryMethod.invoke(emp, new Object[]{500.0f});
System.out.println(emp);
Field成员对象类
- Field对应某个具体类中的成员变量的声明
- Field对象使用classObj.getField方法获取
- 通过Field对象可为某对象成员变量赋值/取值
Field类核心方法
- classObj.getField():获取指定public修饰的成员变量对象
- fieldObj.set():为某对象指定成员变量赋值
- fieldObj.get():获取某对象指定成员变量数值
1.通过Class.forName()方法将指定的类加载到jvm,并返回对应Class对象,如下例的employeeClass
2.通过Class类的对象调用getConstructor方法,获得指定的public修饰构造方法Constructor对象。
3.通过Constructor对象的newInstance方法调用指定类的带参构造函数进行实例化。
4.通过Class的对象调用getField方法,得到Field类的对象,需要给出参数,指定的成员变量名称。
5.通过Field的对象调用get方法,获取对应的成员变量的值。需要给出指定的对象
6.通过Field的对象调用set方法,设置对应成员变量的值,需要给出指定的对象,以及实参。
Class employeeClass = Class.forName("com.imooc.reflect.entity.Employee");
Constructor constructor= employeeClass.getConstructor(new Class[]{
//对于已有的类来说已被加载,自然可以通过.class属性得到对应的类对象
Integer.class, String.class, Float.class, String.class
});
Employee employee = (Employee)constructor.newInstance(new Object[]{
100, "李东", 3000f, "研发部"
});
// 通过Class类的对象获取指定public修饰的成员变量对象,需要给出String类型的成员变量的名字
Field nameField= employeeClass.getField("ename");
System.out.println(employee);
// 通过成员变量对象的set方法,需要给出两个参数,指定的对象,实参,来设置指定对象的指定成员变量
nameField.set(employee, "Lucy");
// 通过成员变量对象的get方法,只要给出一个参数,指定的对象,就可以获取指定对象的指定的成员变量
System.out.println((String)nameField.get(employee));
System.out.println(employee);
getDeclared系列方法
- getDeclaredConstructor(s) | Method(s) | Field(s):获取对应对象
- getConstructor(s) | Method(s) | Field(s):只能获取public对象
- 访问非作用域内构造方法、方法、成员变量,会抛出异常
- 通过Class.forName()方法将指定的类加载到jvm,并返回对应Class对象,如下例的employeeClass
- 通过Class类的对象调用getConstructor方法,获得指定的public修饰构造方法Constructor对象。
- 通过Constructor对象的newInstance方法调用指定类的带参构造函数进行实例化。
- 通过Class类的对象调用getDeclaredFields方法,得到Field对象的数组,每一个元素是一个成员变量的信息,包括修饰符、类型、名字(包名+类名+成员变量名),例如:private java.lang.Integer com.imooc.reflect.entity.Employee.eno,可以获取到所有的成员变量的信息
- public修饰的和非public修饰的访问的方法不一样,通过getModifiers()方法的返回值判断修饰符
- 对于修饰符是public的即getModifiers()为1的,可以直接通过field对象get方法访问成员变量的值,需要传入指定的对象
- 对于修饰符是private的,外部不能直接访问成员变量,而是需要借助指定对象的public修饰的get和set方法。例如此处我们先要拼出get方法的名称,通常是get+成员变量名的首字母大写。通过field对象的getName方法可以拿到成员变量名,就可以拼出方法名。这边需要借助Method类的对象。先通过Class类的对象调用getMethod得到Method的对象,在通过Method的对象调用invoke,运行指定对象的指定方法拿到结果。
Class employeeClass = Class.forName("com.imooc.reflect.entity.Employee");
Constructor constructor= employeeClass.getConstructor(new Class[]{
//对于已有的类来说已被加载,自然可以通过.class属性得到对应的类对象
Integer.class, String.class, Float.class, String.class
});
Employee employee = (Employee)constructor.newInstance(new Object[]{
100, "李东", 3000f, "研发部"
});
// 获取所有的成员变量的信息
Field[] fields= employeeClass.getDeclaredFields();
for(Field field: fields){
System.out.println(field);
}
for(Field field: fields){
// field.getModifiers()获取修饰符,返回整书类型
if(field.getModifiers() == 1){ // public修饰
// public的可以直接获取
System.out.println(field.getName() + ": " + field.get(employee));
}else if(field.getModifiers() == 2){ // private修饰
// private的成员变量,需要借助他们的public修饰的get方法
// 拼private修饰的成元变量的public的get方法的方法名
String methodName = "get" + field.getName().substring(0, 1).toUpperCase()
+ field.getName().substring(1);
// 获取指定方法名的Method对象,get没有参数,由于是可变列表,只需要传指定对象即可
Method method= employeeClass.getMethod(methodName);
// Method对象调用invoke,调用指定的方法,此处不能强转,因为get返回值类型不同
System.out.println(field.getName() + ": " + method.invoke(employee));
}
}