什么是反射?
反射就是允许对成员变量、成员方法和构造方法的信息进行编程访问。换句话来讲,就是通过反射,我们可以在不需要创建其对象的情况下就可以获取其定义的各种属性值以及方法。常见的应用就是IDEA中的提示功能,当我们使用某个对象,使用"."的时候,IDEA会自动进行提示,会弹出一个显示关于该对象所有能调用的方法。
想要使用反射,首先要先创建某个对象的字节码对象,常见的创建方式有以下几种,(第一种的地址可以在IDEA中使用右键复制其引用):
代码编写
这里我们采用第一种进行创建:
package com.wxy.instance;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.Arrays;
public class ClassTest {
public static void main(String[] args) throws ClassNotFoundException, InvocationTargetException, InstantiationException, IllegalAccessException {
//获得字节码对象
Class<?> clazz = Class.forName("com.wxy.instance.Student");
//调用获取构造列表,并选择其中的第3个
Constructor<?>[] declaredConstructors = clazz.getDeclaredConstructors();
System.out.println(Arrays.toString(declaredConstructors));
Constructor<?> declaredConstructor = declaredConstructors[2];
//由于我的对象中第3个构造方法是private修饰,不允许外部调用,所以我们需要使用调用下面的方法,临时取消权限的校验
declaredConstructor.setAccessible(true);
//通过获得的构造方法使用newInstance()可以创建对象
Student xiaoming = (Student) declaredConstructor.newInstance("xiaoming");
System.out.println(xiaoming);
}
}
以下是示例对象:
package com.wxy.instance;
public class Student {
private Integer id;
private String name;
private Integer age;
public Student() {
}
private Student(String name) {
this.name = name;
}
private Student(Integer id, String name, Integer age) {
this.id = id;
this.name = name;
this.age = age;
}
/**
* 获取
* @return id
*/
public Integer getId() {
return id;
}
/**
* 设置
* @param id
*/
public void setId(Integer id) {
this.id = id;
}
/**
* 获取
* @return name
*/
public String getName() {
return name;
}
/**
* 设置
* @param name
*/
public void setName(String name) {
this.name = name;
}
/**
* 获取
* @return age
*/
public Integer getAge() {
return age;
}
/**
* 设置
* @param age
*/
public void setAge(Integer age) {
this.age = age;
}
public String toString() {
return "Student{id = " + id + ", name = " + name + ", age = " + age + "}";
}
/**
* 测试反射获取成员方法
* @param arg
*/
private String testMethodGet(String arg){
System.out.println(this.name + "调用调用成功,传递的参数是" + arg);
return "调用成功";
}
}
除了获取构造方法,我们还可以使用反射获取其成员变量,包括其记录值、修饰符、数据类型等。
//在刚刚我们使用反射创建了一个对象
Student xiaoming = (Student) declaredConstructor.newInstance("xiaoming");
System.out.println(xiaoming);
//我们使用字节码对象调用其方法获得我们的成员变量name
Field name = clazz.getDeclaredField("name");
//由于其变量是private修饰,所以我们需要禁用其权限校验
name.setAccessible(true);
//通过get方法可以获取其记录值
String nameByXiaoMing = (String) name.get(xiaoming);
System.out.println(nameByXiaoMing);
//使用set可以修改其记录值
name.set(xiaoming,"xiaohong");
System.out.println(name.get(xiaoming));
结果如下:
同样我们还可以获得其内部方法:
//获取方法
Method testMethodGet = clazz.getDeclaredMethod("testMethodGet", String.class);
//由于该方法时private
testMethodGet.setAccessible(true);
//需要传入调用的对象以及调用所需的参数,如果是空参可省略,有返回值则可以进行接收
String result = (String) testMethodGet.invoke(xiaoming, "塔斯汀");
System.out.println(result);
结果如下: