概述
能够分析类能力的程序称为反射。
- 在运行时构造任意类的对象
- 在运行时获取或修改任意类所有的方法和属性
- 在运行时调用任意类的方法和属性
Class
反射基于Class,没有Class不谈反射。Class类封装了当前对象对应类所有方法和属性,Class属于类的类,拿到Class就能拿到所有的对应类的方法和属性并做些什么。
获取Class对象
获取Class对象方式有三种:
- 通过类名.class直接获取。
// 通过类直接获取
Class<ReflectTest> reflectTestClass = ReflectTest.class;
Class<Integer> integerClass = int.class;
Class<Integer> type = Integer.TYPE;
System.out.println("通过类直接获取00:" + reflectTestClass.getName());
System.out.println("通过类直接获取01:" + integerClass.getName());
System.out.println("通过类直接获取02:" + type.getName());
运行:
通过类直接获取00:ReflectTest
通过类直接获取01:int
通过类直接获取02:int
- 通过对象名.getClass获取。
ReflectTest reflectTest = new ReflectTest();
Class<? extends ReflectTest> aClass = reflectTest.getClass();
System.out.println("通过对象名.getClass()获取:" + aClass.getName());
运行:
通过对象名.getClass()获取:ReflectTest
- 通过全类名获取。
Class提供的静态方法:
*/
@CallerSensitive
public static Class<?> forName(String className)
throws ClassNotFoundException {
Class<?> caller = Reflection.getCallerClass();
return forName0(className, true, ClassLoader.getClassLoader(caller), caller);
}
通过全类名获取类对象。
String className = "ReflectTest";
try {
Class<?> aClass1 = Class.forName(className);
System.out.println("通过全类名获取:" + aClass1.getName());
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
运行:
通过全类名获取:ReflectTest
判断类的类型与实例
String className = "ReflectTest";
try {
Class<?> aClass1 = Class.forName(className);
Class<?> aClass2 = Class.forName(className);
System.out.println(aClass1 == aClass2);
// 判断是否是某个类的实例
boolean instance = ReflectTest.class.isInstance(aClass1);
System.out.println(instance ? "是ReflectTest的实例" : "不是ReflectTest的实例");
// 判断是否是某一个类的类型
boolean assignableFrom = reflectTestClass.isAssignableFrom(ReflectTest.class);
System.out.println(assignableFrom ? "是ReflectTest类型" : "不是ReflectTest类型");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
运行:
true
不是ReflectTest的实例
是ReflectTest类型
使用==判断结果为true,是因为没有创建实例,两个对象都指向同一个class文件,所以为true。
- 通过native方法isInstance()判断是不是某一个类的实列。
public native boolean isInstance(Object obj);
代码中只是根据类名的字符串获取到相对应的类,并没有创建该类的对象,所以返回结果正确。
- 通过isAssignableFrom()判断是不是某一个类的类型。
代码中获取的类和ReflectTest肯定是同一类型,所以运行结果无误。
创建实例
通过反射创建实例有两种方式:通过调用newInstance()方法创建实例;通过先获取Constructor对象,通过Constructor对象调用newInstance()创建实例。
public class ReflectTest {
public ReflectTest() {
System.out.println("这是ReflectTest的构造");
}
}
- newInstance()。
String className = "ReflectTest";
try {
Class<?> aClass1 = Class.forName(className);
Object newInstance = aClass1.newInstance();
// 判断是否是某个类的实例
boolean instance = ReflectTest.class.isInstance(newInstance);
System.out.println(instance ? "是ReflectTest的实例" : "不是ReflectTest的实例");
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
}
运行:
是ReflectTest的实例
- 先获取Constructor,再调用newInstance。
String className = "ReflectTest";
try {
Class<?> aClass1 = Class.forName(className);
// 获取构造
Constructor<?> constructor = aClass1.getConstructor(ReflectTest.class);
// 通过构造获取实例
Object instance1 = constructor.newInstance();
// 判断是否是某个类的实例
boolean instance = ReflectTest.class.isInstance(instance1);
System.out.println(instance ? "是ReflectTest的实例" : "不是ReflectTest的实例");
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
运行:
修改:
try {
Class<ReflectTest> aClass1 = ReflectTest.class;
// 获取所有构造
Constructor<?>[] constructor = aClass1.getConstructors();
Object instance1 = constructor[0].newInstance();
// 判断是否是某个类的实例
boolean instance = ReflectTest.class.isInstance(instance1);
System.out.println(instance ? "是ReflectTest的实例" : "不是ReflectTest的实例");
} catch (Exception e) {
e.printStackTrace();
}
运行:
这是ReflectTest的构造
是ReflectTest的实例
除了调用getConstructors()可以得到正确的结果外,调用getConstructor(),getDeclaredConstructor()均出现java.lang.NoSuchMethodException异常,详细原因如下:
方法 | 描述 |
---|---|
getConstructor(Class<?>… parameterTypes) | 获取使用特殊参数类型的public构造,包含父类 |
getConstructors() | 获取所有公共构造 |
getDeclaredConstructors() | 获取所有的构造 |
getDeclaredConstructor(Class<?>… parameterTypes) | 获取所有使用特殊参数的构造 |
获取成员变量
public class ReflectTest {
// 共有
public String name = "名称";
// 私有
private int age = 23;
// 默认
boolean female = true;
// 受保护
protected double salary = 2022.22;
}
获取所有成员变量
String className = "ReflectTest";
try {
// 获取类对象
Class<?> aClass = Class.forName(className);
// 获取所有成员变量
Field[] fields = aClass.getFields();
for (Field field : fields) {
// 打印所有成员变量
System.out.println(field);
System.out.println(field.getName());
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
结果:
public java.lang.String ReflectTest.name
name
getFields()只能获取公共的成员变量,其他的都无法获取。使用getDeclaredFields()可以获取所有申明的成员变量。
// 获取所有成员变量
Field[] fields = aClass.getDeclaredFields();
for (Field field : fields) {
// 打印所有成员变量
System.out.println(field);
System.out.println(field.getName());
}
运行:
public java.lang.String ReflectTest.name
name
private int ReflectTest.age
age
boolean ReflectTest.female
female
protected double ReflectTest.salary
salary
获取成员变量的权限修饰
// 获取所有成员变量
Field[] fields = aClass.getDeclaredFields();
for (Field field : fields) {
// 打印所有成员变量
System.out.println(field);
// 权限修饰
System.out.println(field.getModifiers());
}
运行:
public java.lang.String ReflectTest.name
1
private int ReflectTest.age
2
boolean ReflectTest.female
0
protected double ReflectTest.salary
4
权限与其对应的值。
权限 | 反射中对应的值 |
---|---|
public | 1 |
private | 2 |
protected | 4 |
default | 0 |
获取成员变量的值
获取成员变量的值,必须先创建对象,没有对象就没有成员变量。
try {
...
// 创建实例
ReflectTest reflectTest = new ReflectTest("test");
// 获取所有成员变量
Field[] fields = aClass.getFields();
for (Field field : fields) {
// 打印所有成员变量
System.out.println(field);
System.out.println(field.getName());
System.out.println(field.get(reflectTest));
}
...
}
结果:
这是ReflectTest的构造
public java.lang.String ReflectTest.name
name
名称
已经获取到属性name的值“名称”。
修改公共成员变量的值
// 获取指定成员变量
Field nameField = aClass.getField("name");
// 修改成员变量的值
nameField.set(reflectTest,"狗子");
// 输出,检查修改是否成功
System.out.println(reflectTest.name);
运行:
名称
狗子
原来name的值是“名称”,已被修改成“狗子”。
修改私有成员变量的值
// 获取指定成员变量
Field ageField = aClass.getDeclaredField("age");
// 暴力反射,突破权限限制
ageField.setAccessible(true);
// 修改成员变量的值
ageField.set(reflectTest,18);
// 输出,检查修改是否成功
System.out.println(reflectTest.getAge());
运行:
18
原来是23,现在修改成18,修改成功。
访问static变量
static字段:
private static String power = "石油";
修改字段:
String className = "ReflectTest";
try {
// 获取类对象
Class<?> aClass = Class.forName(className);
// 创建实例
ReflectTest reflectTest = new ReflectTest("test");
// 获取字段
Field power = aClass.getDeclaredField("power");
//
power.setAccessible(true);
// 修改
power.set(reflectTest,"太阳");
Object obj = power.get(reflectTest);
System.out.println("static修改后的值:" + obj.toString());
} catch (Exception e) {
e.printStackTrace();
}
运行:
static修改后的值:太阳
修改final成员
final字段:
private final String address = "杭州";
public void showAddress() {
System.out.println("final修改后的值:" + address);
}
修改:
String className = "ReflectTest";
try {
// 获取类对象
Class<?> aClass = Class.forName(className);
// 创建实例
ReflectTest reflectTest = new ReflectTest("test");
// 获取字段
Field address = aClass.getDeclaredField("address");
//
address.setAccessible(true);
// 修改
address.set(reflectTest,"武汉");
// 打印
reflectTest.showAddress();
} catch (Exception e) {
e.printStackTrace();
}
运行:
final修改后的值:杭州
发现修改失败,因为JVM对final进行了优化,其实是修改成功了,只是打印的那个值没有变化,就是编译的时候打印输出的值已经固定了,和它后来是什么样的没有关系了。即:
System.out.println("final修改后的值:" + address);
被优化成:
System.out.println("final修改后的值:" + "杭州");
所以需要修改完后再取出来进行打印输出。
// 获取类对象
Class<?> aClass = Class.forName(className);
// 创建实例
ReflectTest reflectTest = new ReflectTest("test");
// 获取字段
Field address = aClass.getDeclaredField("address");
//
address.setAccessible(true);
// 修改
address.set(reflectTest,"武汉");
// 打印
// reflectTest.showAddress();
// 将修改的字段单独取出来进行输出
Object obj = address.get(reflectTest);
System.out.println("final修改后的值:" + obj.toString());
运行:
final修改后的值:武汉
修改static final字段
static final 字段:
private static final String area = "西北";
修改:
String className = "ReflectTest";
try {
// 获取类对象
Class<?> aClass = Class.forName(className);
// 创建实例
ReflectTest reflectTest = new ReflectTest("test");
// 获取字段
Field area = aClass.getDeclaredField("area");
//
area.setAccessible(true);
// 修改
area.set(reflectTest,"东北");
Object obj = area.get(reflectTest);
System.out.println("static final修改后的值:" + obj.toString());
} catch (Exception e) {
e.printStackTrace();
}
运行:
修正:修改时需要先把final修饰符拿掉,修改完后再把final修饰符加上去。
String className = "ReflectTest";
try {
// 获取类对象
Class<?> aClass = Class.forName(className);
// 创建实例
ReflectTest reflectTest = new ReflectTest("test");
// 获取字段
Field area = aClass.getDeclaredField("area");
//
area.setAccessible(true);
// 获取final修饰符
Field modifiers = area.getClass().getDeclaredField("modifiers");
// 暴力反射
modifiers.setAccessible(true);
// 拿掉final修饰符
modifiers.setInt(area,area.getModifiers() &~Modifier.FINAL);
// 修改
area.set(reflectTest,"东北");
// 添加final修饰符
modifiers.setInt(area,area.getModifiers() &~Modifier.FINAL);
Object obj = area.get(reflectTest);
System.out.println("static final修改后的值:" + obj.toString());
} catch (Exception e) {
e.printStackTrace();
}
运行:
static final修改后的值:东北
获取方法
public class ReflectTest {
public int getAge() {
return age;
}
// 私有方法
private void reflectMethod01(){
}
// 共有方法
public void reflectMethod02(){
}
// 共有带参方法
public void reflectMethod03(String param){
}
// 共有带参带返回值的方法
public String reflectMethod04(String param){
System.out.println("参数:" + param);
return param;
}
public ReflectTest(String aaa) {
System.out.println("这是ReflectTest的构造");
}
}
获取所有声明的方法
try {
// 获取类对象
Class<?> aClass = Class.forName(className);
// 创建实例
//ReflectTest reflectTest = new ReflectTest("test");
// 获取所有方法
Method[] methods = aClass.getDeclaredMethods();
for (Method mothod : methods) {
// 打印所有方法
System.out.println(mothod);
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
运行:
public int ReflectTest.getAge()
public void ReflectTest.reflectMethod02()
public void ReflectTest.reflectMethod03(java.lang.String)
private void ReflectTest.reflectMethod01()
public java.lang.String ReflectTest.reflectMethod04(java.lang.String)
没有返回构造方法,因为构造方法有单独的方法进行调用,这里不用。
方法 | 描述 |
---|---|
getDeclaredMethods() | 返回所有成员方法,不包括继承的 |
getDeclaredMethod(String name, Class<?>… parameterTypes) | 返回某一个具体的成员方法 |
getMethods() | 返回所有公共成员方法,包括继承的 |
getMethod(String name, Class<?>… parameterTypes) | 返回某一个指定的成员方法 |
调用公共成员方法
成员方法:
// 共有带参带返回值的方法
public String reflectMethod04(String param){
System.out.println("参数:" + param);
return param;
}
反射调用成员方法。
// 获取方法
Method reflectMethod04 = aClass.getMethod("reflectMethod04", String.class);
// 调用方法并获取返回值
Object returnValue = reflectMethod04.invoke(reflectTest, "happy");
// 打印返回值
System.out.println("成员方法返回值:" + returnValue);
运行:
参数:happy
成员方法返回值:happy
调用私有成员变量
成员方法:
// 私有方法
private void reflectMethod01(){
System.out.println("这个是私有成员方法");
}
反射调用私有成员方法
Method reflectMethod01 = aClass.getDeclaredMethod("reflectMethod01");
// 暴力反射,突破权限
reflectMethod01.setAccessible(true);
// 调用方法
reflectMethod01.invoke(reflectTest);
运行:
这个是私有成员方法