1.什么是反射
在
运行状态
中, 能够动态
的获取以及调用对象的信息
2.Class文件包含的内容
3.反射关键类图
Member
: 有关单个成员(字段或方法)或构造函数的标识信息的接口AccessibleObject
:Field
、Method
和Constructor
对象的基类(在反射对象中设置accessible
标志允许具有足够特权)Field
: 提供有关类或接口的单个字段的信息和动态访问, 包括类(静态)字段、实例字段Executable
:Method
和Constructor
通用功能的超类Method
: 提供有关类或接口上的单个方法的信息和对其的访问, 包含类方法、实例方法(抽象方法)Constructor<T>
: 提供有关类的单个构造函数的信息和对其的访问
4.基础应用
1.获取Class
对象的方式:
Class.forName()
Class<String> clazz = (Class<String>) Class.forName("java.lang.String");
对象.class
Class<String> clazz = String.class;
对象实例.getClass()
Class<String> clazz = (Class<String>) "".getClass();
2.生成实例
// 普通生成实例
String str = new String();
// 反射生成实例
// 1. 获取Class对象
Class<String> clazz = (Class<String>) Class.forName("java.lang.String");
// 2. 获取构造函数对象
Constructor<String> constructor = clazz.getConstructor();
// 3. 获取实例
String str = constructor.newInstance();
3.获取对象信息
例如: 存在一个Person类
public class Person {
public Person(int age, String name) {
this.age = age;
this.name = name;
}
public int age;
private String name;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
- 获取Person对象
Class<Person> clazz = Person.class;
// 因为Person只有有参构造, 所以这边同样使用了有参
Constructor<Person> constructor = clazz.getConstructor(int.class, String.class);
Person person = constructor.newInstance(18, "反射");
- 成员变量
Field ageField = clazz.getField("age");
int age1 = (int) ageField.get(person);
// age1: 18
System.out.println(age1);
// name是由private修饰, 直接使用getField()方法获取失败
// Field nameField = clazz.getField("name");
// 此设置无效: 因为在程序走到此步前, 已经返回NoSuchFieldException错误
// nameField.setAccessible(true);
Field nameDeclaredField = clazz.getDeclaredField("name");
// 关键一步: 获取访问权限, 如缺失, 则依旧访问失败
nameDeclaredField.setAccessible(true);
String name = (String) nameDeclaredField.get(person);
// name: 反射
System.out.println(name);
- 函数
// 对于private修饰的方法, 同成员变量的规则
Method setAge = clazz.getMethod("setAge", int.class);
setAge.invoke(person, 20);
Method getAge = clazz.getMethod("getAge");
int age2 = (int) getAge.invoke(person);
// age2: 20(18 -> 20)
System.out.println(age2);
总结
getxx
: 能访问使用public修饰的, 并且包括超类的所有信息
getDeclaredxx
: 只能访问本类的所有信息
-
public
:getxx
和getDeclaredxx
都行 -
protected
:getDeclaredxx
就行 -
default
(无):getDeclaredxx
就行 -
private
:getDeclaredxx
同时需设置xx.setAccessible(true)
-
正常使用时: 可直接使用
getDeclaredxx
+xx.setAccessible(true)
进行操作