Java中反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为Java语言的反射机制
一、反射原理
-
类加载到内存
-
加载器自动为.class文件创建一个对象
-
在自己的程序中获取到.class文件
二、获取一个类的 class 文件对象的三种方式
-
对象获取:通过对象继承的Object的方法getClass()
-
类名获取:通过每个类型都拥有的静态方法.class获取
-
Class 类的静态方法获取:Class 类的静态方法forName(包名+类名)获取
public static void main(String[] args) throws ClassNotFoundException {
//1.对象获取
Student student = new Student();
Class clazz = student.getClass();
//2.类名获取
Class clazz2 = Student.class;
//3.类的静态方法获取
Class clazz3 = Class.forName("com.example.Student");
}
三、获取class 文件中的成员
1. 使用反射获取无参构造方法并运行
-
Constructor getConstructor():获取指定的空参构造方法
-
Constructor[] getConstructors(): 获取class文件对象中的所有公共的构造方法,返回的是构造方法的数组
-
newInstance():运行构造函数
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
Class clazz = Class.forName("com.example.Student");
Constructor con = clazz.getConstructor();
Object obj = con.newInstance();
System.out.println(obj);
}
2. 使用反射获取有参构造方法并运行
-
Constructor< T > getConstructor(Class<?>... parameterTypes):获得指定的构造方法,传递要获取的构造方法的参数列表
-
Object newInstance(Class<?>... parameterTypes):运行构造方法,传递可变参数
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
Class clazz = Class.forName("com.example.Student");
Constructor con = clazz.getConstructor(String.class,int.class);
Object obj = con.newInstance("张三",18);
System.out.println(obj);
}
3. 反射获取构造方法并运行的快捷方式
-
被反射的类必须有空参构造函数
-
构造方法必须是 public 权限
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
Class clazz = Class.forName("com.example.Student");
Object obj = clazz.newInstance();
System.out.println(obj);
}
4. 反射获取私有构造方法并运行(暴力反射)
-
Constructor getConstructor():获取指定参数的构造方法
-
Constructor类的父类AccessibleObject类的方法setAccessible(boolean b),参数为true的时候能取消访问检查
-
不推荐,破坏了程序的封装性和安全性
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
Class clazz = Class.forName("com.example.Student");
Constructor con = clazz.getDeclaredConstructor(String.class,int.class);
con.setAccessible(true);
Object obj = con.newInstance("张三",18);
System.out.println(obj);
}
5. 反射获得成员变量并修改
-
Field getField():获取指定的公有成员变量,通过 set() 方法来修改对象的成员变量
-
Field getField():获取指定的私有成员变量,使用setAccessible(true)取消访问检查,通过 set() 方法来修改对象的成员变量
-
Field[] getFields():获取成员变量Class类的方法getFields() class文件中所有公共的成员变量,返回 Field[] 数组
-
Field[] getDeclaredFields():获得所有私有成员变量
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, NoSuchMethodException, InvocationTargetException, IllegalAccessException, NoSuchFieldException {
Class clazz = Class.forName("com.example.Student");
Object obj = clazz.newInstance();
//获取所有私有成员变量
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
System.out.println(field);
}
//获取单个私有成员变量
Field field = clazz.getDeclaredField("age");
field.setAccessible(true);
field.set(obj,10);
System.out.println(obj);
}
6. 反射获得成员方法并运行
-
Method[] getMethods():获得class文件中所有公共成员方法
-
Method getMethod(String name, Class<?>... parameterTypes):获得指定成员方法,name为要获取的方法名,parameterTypes为参数列表
-
meth.invoke(obj):运行方法:使用Method类中的方法
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, NoSuchMethodException, InvocationTargetException, IllegalAccessException, NoSuchFieldException {
Class clazz = Class.forName("com.example.Student");
Object obj = clazz.newInstance();
//获取所有公共成员方法
Method[] methods = clazz.getMethods();
//获取所有私有成员方法
// Method[] methods = clazz.getDeclaredMethods();
for (Method method : methods) {
System.out.println(method);
}
//获取指定的公共成员方法并运行
Method method = clazz.getMethod("study");
method.invoke(obj);
//获取指定的私有成员方法并运行
Method method1 = clazz.getDeclaredMethod("speak");
method1.setAccessible(true);
method1.invoke(obj);
}
7. 反射泛型擦除
通过反射将泛型擦除,存储泛型之外的内容
public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
List<Integer> list = new ArrayList<>();
Class clazz = list.getClass();
Method method = clazz.getMethod("add",Object.class);
method.invoke(list,"张三");
method.invoke(list,"李四");
method.invoke(list,"王五");
System.out.println(list);
}