反射就是通过字节码文件获取类的成员变量、构造方法和成员方法的所有信息。
利用反射,我们可以获取成员变量的修饰符、名字、类型、取值。我们可以获取构造方法的名字、形参,并利用通过反射获取的构造方法创建对象。我们可以获取成员方法的修饰符、名字、形参、返回值、抛出的异常、注解,并运行通过反射获取的方法。
比如idea中的自动提示就是通过反射获取的,idea通过反射获取该对象的所有能调用的方法,并将它显示出来,又比如idea中函数的形参提示也是通过反射获取的。
反射是通过字节码文件对象获取成员变量、成员方法、构造方法的所有信息,所以,我们先要获取字节码文件对象,再去从字节码文件对象中获取成员变量、构造方法和成员方法,最后再进行解剖获取所有信息。
获取class对象的3种方式:
(1)class.forName("全类名");
(2)类名.class;
(3)对象.getClass();
那我们应该如何选择呢?
创建一个类的对象,我们需要经历以下3个阶段:
- 源代码阶段:Java->class,在这个阶段,虚拟机是没有把代码加载到内存当中的,全都是硬盘中进行操作。在这个阶段用第一种方式获取class字节码文件对象。第一种方式最为常用。
- 加载阶段:把字节码文件加载到内存中。这个阶段使用第二种方式来获取字节码文件对象。第二种方式通常都是当作参数进行传递。
- 运行阶段:在该阶段使用第三种方式。当我们已经有了这个类的对象时才可以使用第三种方式。
利用反射获取构造方法:
Constructor<?>[] getConstructors()//返回所有公共构造方法对象的数组
Constructor<?>[] getDeclaredConstructors()//返回所有构造方法对象的数组
Constructor<T> getConstructor(Class<?>..parameterTypes)//返回单个公共构造方法对象
Constructor<T> getDeclaredConstructor(Class<?>.. parameterTypes)//返回单个构造方法对象
T newInstance(Object... initargs)//根据指定的构造方法创建对象
setAccessible(boolean flag)//设置为true可以绕过访问控制权限,使得 private 属性或方法也可以被访问。
//setAccessible(boolean flag)使用示例
public class Example {
private String privateField = "privateValue";
}
public class AnotherClass {
public static void main(String[] args) throws Exception {
Example instance = new Example();
Field field = Example.class.getDeclaredField("privateField");
field.setAccessible(true);
System.out.println("Private Field Value: " + field.get(instance)); // 可以通过反射访问私有字段
}
}
Class类中用于获取成员变量的方法:
Field[] getFields()//返回所有公共成员变量对象的数组
Field[] getDeclaredFields()//返回所有成员变量对象的数组
Field getField(String name)//返回单个公共成员变量对象
Field getDeclaredField(Stringname)//返回单个成员变量对象
void set(Object obj, Object value)//给成员变量赋值
Object get(Object obj)//获取成员变量的值。
setAccessible(boolean flag)//使用 setAccessible(true) 可以绕过访问控制权限,使得 private 属性或方法也可以被访问。
//set,get示例
public class Example {
private String name;
private int age;
public static void main(String[] args) throws Exception {
Example example = new Example();
Field nameField = Example.class.getDeclaredField("name");
Field ageField = Example.class.getDeclaredField("age");
// 设置字段值
nameField.set(example, "John Doe");
ageField.set(example, 30);
// 获取字段值
System.out.println("Name: " + nameField.get(example));
System.out.println("Age: " + ageField.get(example));
}
}
Class类中用于获取成员方法的方法:
Method[] getMethods()//返回类中所有公共成员方法对象的数组,包括继承的
Method[] getDeclaredMethods()//返回类中所有成员方法对象的数组,不包括继承的
Method getMethod(String name, Class<?>... parameterTypes)//返回单个公共成员方法对象
Method getDeclaredMethod(String name, Class<?>... parameterTypes)//返回单个成员方法对象
Object invoke(Object obj,Object... args)//运行方法
//参数一:用obj对象调用该方法
//参数二:调用方法的传递的参数(如果没有就不写)
//返回值:方法的返回值(如果没有就不写)
setAccessible(boolean flag)//使用 setAccessible(true) 可以绕过访问控制权限,使得 private 属性或方法也可以被访问。
//invoke使用示例:
public class Example {
public void greet(String name) {
System.out.println("Hello, " + name + "!");
}
public static void main(String[] args) throws Exception {
Example example = new Example();
Method method = Example.class.getMethod("greet", String.class);
// 调用 greet 方法
method.invoke(example, "John");
}
}
注意:获取公共方法时也会获取父类中的所有公共方法。获取所有权限的方法时,就不会获取父类的方法