java反射
之前只是浅浅了解了一下,现在来深度学习一下
什么是java反射机制?
Java反射机制是指在运行时动态地获取一个类的信息,以及在运行时动态地创建对象、调用方法、访问属性等操作。Java反射机制提供了许多方法来获取一个类的信息,包括类的名称、父类、接口、构造方法、方法、字段等。通过反射,可以在运行时动态地创建对象,而不需要在编译时确定对象的类型。
相关的类
java.lang.Class 代表整个字节码。代表一个类型,代表整个类。
java.lang.reflect.Method 代表字节码中的方法字节码。代表类中的方法。
java.lang.reflect.Constructor 代表字节码中的构造方法字节码。代表类中的构造方法。
java.lang.reflect.Field 代表字节码中的属性字节码。代表类中的成员变量(静态变量+实例变量)。
注意:必须要先获得类,才能进一步获得类的方法和属性
获取class的三种方法
要操作一个类的字节码,需要首先获取到这个类的字节码,我们应该怎么获取java.lang.Class实例呢?
1 2 3 4 5
| Class.forName(“完整类名带包名”):使用这种方法会调用该类的静态代码模块,例如Class.forName("java.lang.String")
对象.getClass()
任何类型.class
|
示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| package src;
import java.util.Arrays;
public class ReflectTest2 { public static void main(String[] args) throws Exception { String str = "ycxlo"; Class clazz = str.getClass(); System.out.println(clazz.getName()); System.out.println(clazz.getSimpleName()); System.out.println(clazz.getSuperclass()); System.out.println(Arrays.toString(clazz.getInterfaces())); } }
|
输出:
1 2 3 4
| java.lang.String String class java.lang.Object [interface java.io.Serializable, interface java.lang.Comparable, interface java.lang.CharSequence]
|
通过反射获取实例化对象
注:newInstance()方法内部实际上调用了无参数构造方法,必须保证无参构造存在才可以。
否则会抛出java.lang.InstantiationException
异常。
示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| package src;
import java.util.Arrays;
public class ReflectTest2 { public static void main(String[] args) throws Exception { String className = "src.test"; Class clazz = Class.forName(className); Object obj = clazz.newInstance(); System.out.println(obj.toString()); } }
|
test.java
1 2 3 4 5 6 7 8 9
| package src;
import java.util.Scanner;
public class test{ public String toString(){ return "ycxlo"; } }
|
也可以通过Constructor的newInstance()方法创建对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| package src;
import java.lang.reflect.Constructor;
public class ReflectTest2 { public static void main(String[] args) throws Exception { String className = "src.test"; Class clazz = Class.forName(className); Constructor con = clazz.getConstructor(); Object obj = con.newInstance(); System.out.println(obj); } }
|
还可以这样:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| package src;
import java.lang.reflect.Constructor; import java.lang.reflect.Method;
public class ReflectTest2 { public static void main(String[] args) throws Exception { String className = "src.test"; Class clazz = Class.forName(className); Object test = clazz.getConstructor().newInstance(); Method m1 = clazz.getMethod("toString"); System.out.println(m1.invoke(test)); } }
|
1 2 3 4 5 6 7 8 9 10 11
| invoke() 是 Java 反射 API 中的一个方法,用于动态地调用方法或构造函数。
在 Java 中,我们可以使用 Method 类的 invoke() 方法来调用具有相应参数的方法。类似地,我们也可以使用 Constructor 类的 newInstance() 方法来创建对象。
invoke() 方法接受两个参数:
第一个参数是要调用方法或构造函数的对象实例,如果方法是静态的,则传入 null。 第二个参数是要传递给方法或构造函数的参数列表,以可变参数的形式提供。 调用 invoke() 方法后,它将执行相应的方法或构造函数,并且返回结果(如果方法有返回值)。如果方法或构造函数抛出异常,invoke() 方法也会抛出相应的异常。
在代码示例中,m1.invoke(test) 使用反射调用了 test 对象的 toString() 方法。这将会执行 test.toString(),并返回其结果。
|
反射Filed(字段)
class类方法
public T newInstance() 创建对象
public String getName() 返回完整类名带包
public String getSimpleName() 返回类名
public Field[] getFields() 返回类中public修饰的属性
public Field[] getDeclaredFields() 返回类中所有的属性
public Field getDeclaredField(String name) 根据属性名name获取指定的属性
public native int getModifiers() 获取属性的修饰符列表,返回的修饰符是一个数字,每个数字是修饰符的代号【一般配合Modifier类的toString(int x)方法使用】
public Method[] getDeclaredMethods() 返回类中所有的实例方法
public Method getDeclaredMethod(String name, Class<?>… parameterTypes) 根据方法名name和方法形参获取指定方法
public Constructor<?>[] getDeclaredConstructors() 返回类中所有的构造方法
public Constructor getDeclaredConstructor(Class<?>… parameterTypes) 根据方法形参获取指定的构造方法
public native Class<? super T> getSuperclass() 返回调用类的父类
public Class<?>[] getInterfaces() 返回调用类实现的接口集合
Filed类方法
public String getName() 返回属性名
public int getModifiers() 获取属性的修饰符列表,返回的修饰符是一个数字,每个数字是修饰符的代号【一般配合Modifier类的toString(int x)方法使用】
public Class<?> getType() 以Class类型,返回属性类型【一般配合Class类的getSimpleName()方法使用】
public void set(Object obj, Object value) 设置属性值
public Object get(Object obj) 读取属性值
示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| package src;
import java.lang.reflect.Field;
public class ReflectTest { public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException { Class<MyClass> myClassClass = MyClass.class;
Field field = myClassClass.getDeclaredField("myField"); field.setAccessible(true);
MyClass myObject = new MyClass(); System.out.println("Field Value (Before Modification): " + field.get(myObject));
field.set(myObject, "New Value"); System.out.println("Field Value (After Modification): " + field.get(myObject)); } }
class MyClass { private String myField = "Initial Value"; }
|
输出:
1 2
| Field Value (Before Modification): Initial Value Field Value (After Modification): New Value
|
反射修改final static变量
演示代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| package src;
import java.lang.reflect.Field; import java.lang.reflect.Modifier;
public class staticfinaltest {
public static void main(String[] args) throws Exception { Field number = Test.class.getDeclaredField("NUMBER"); setFinalStatic(number, 3); System.out.println(Test.getNumber()); }
private static void setFinalStatic(Field field, Object newValue) throws NoSuchFieldException, IllegalAccessException { field.setAccessible(true); Field modifiersField = Field.class.getDeclaredField("modifiers"); modifiersField.setAccessible(true);
modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL); field.set(null, newValue); } }
class Test{
private static final Integer NUMBER = 1;
public static Integer getNumber() { return NUMBER; } }
|
一点解释:
1 2 3 4 5
| field.setAccessible(true):将 field 对象的可访问性设置为 true,以便我们能够访问并修改该字段。 Field modifiersField = Field.class.getDeclaredField("modifiers"):通过 getDeclaredField 方法获取到 Field 类的名为 "modifiers" 的字段对象,它用于表示字段修饰符。 modifiersField.setAccessible(true):将 modifiersField 对象的可访问性设置为 true,以便我们能够访问并修改该字段的值。 modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL):通过调用 setInt 方法,将 field 对象的修饰符字段的值进行修改。通过按位与操作和取反操作,可以将 FIELD 修饰符中的 FINAL 标志位设为 0,从而达到去除 final 修饰符的目的。 field.set(null, newValue):最后,通过调用 set 方法将新的值 newValue 赋给 field 对象表示的 final static 变量。由于该变量是 static 的,因此使用 null 作为目标对象。对于静态字段,我们不需要通过实例来访问或修改其值,而是直接通过类名来访问。因此,在使用 field.set(null, newValue) 时,null 被用作代替实例的目标对象,表示我们不需要特定的实例来设置静态字段的值。
|
各个修饰符对应的modifiers的值
1 2 3 4 5 6 7
| 第 1 位(从右往左):public 第 2 位:private 第 3 位:protected 第 4 位:static 第 5 位:final 第 6 位:... 第 7 位:...
|
例如,10的二进制是1010,那么对应的就是private static
相当于modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL)
是把原来的final修饰符给删去,以便执行set方法