什么是反射?
是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;
对于任意一个对象,都能够调用它的任意属性和方法;
这种动态获取信息以及动态调用对象方法的功能称为Java语言的反射机制。
字节码文件和字节码文件对象
java文件:就是我们自己编写的java代码。
字节码文件:就是通过java文件编译之后的class文件(是在硬盘上真实存在的,用眼睛能看到的)
字节码文件对象:当class文件加载到内存之后,虚拟机自动创建出来的对象。
这个对象里面至少包含了:构造方法,成员变量,成员方法。
而我们的反射获取的是什么?字节码文件对象,这个对象在内存中是唯一的。
获取字节码文件对象的三种方式
最常用的是第一种通过全类名获取
通过字节码文件对象获取构造方法
其中构造方法的私有对应不同的方法。详情如下:
实例化对象
其中对私有构造方法形参的设置需要修改私有构造方法的访问权限,设置方法为setAccessible(true)。
获取成员变量
不同访问权限的成员变量对应不同的方法,详情如下:
成员变量的赋值与获取
如果要访问私有的成员变量就得修改访问权限。
获取成员方法
成员方法的执行
完整代码如下:
package com.tians.annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
/**
* @date : 2024/1/15 9:57
*/
public class MyTestMethodDemo {
public static void main(String[] args) throws Exception {
// 获取字节码文件对象(三种方式)
Class<?> aClass = getClassObject();
// 获取空参构造
Constructor<?> constructor = aClass.getConstructor();
System.out.println(constructor);
// 获取全参构造
Constructor<?> constructors = aClass.getConstructor(String.class, Integer.class);
System.out.println(constructors);
// 获取指定构造
Constructor<?> constructor1 = aClass.getDeclaredConstructor(String.class); //因为这个构造方法是私有的
System.out.println(constructor1);
Constructor<?> constructor2 = aClass.getDeclaredConstructor(Integer.class); //因为这个构造方法是私有的
System.out.println(constructor2);
// 实例化对象
MyTestMethod object = (MyTestMethod) aClass.newInstance(); // 通过字节码文件对象直接实例化对象
MyTestMethod objectByVoid = (MyTestMethod) constructor.newInstance(); //通过空参构造直接实例化对象
System.out.println(objectByVoid);
MyTestMethod objectByAll = (MyTestMethod) constructors.newInstance("张三",18); // 通过全参构造直接实例化对象
System.out.println(objectByAll+":"+objectByAll.toString());
// 判断是否需要修改私有构造方法的访问权限:私有成员反射需要修改访问权限
constructor1.setAccessible(true);
MyTestMethod objectByPointName = (MyTestMethod) constructor1.newInstance("李四"); // 通过有参构造直接实例化对象
System.out.println(objectByPointName+":"+objectByPointName.getName());
constructor2.setAccessible(true);
MyTestMethod objectByPointAge = (MyTestMethod) constructor2.newInstance(80); // 通过有参构造直接实例化对象
System.out.println(objectByPointAge+":"+objectByPointAge.getAge());
// 获取单个成员变量对象公有
Field name = aClass.getField("name");
// Field age = aClass.getField("age");
System.out.println(name);
// 获取单个成员变量对象公有+私有
Field nameByDeclared = aClass.getDeclaredField("name");
Field ageByDeclared = aClass.getDeclaredField("age");
System.out.println(nameByDeclared+":"+ageByDeclared);
// 获取全部成员变量公有
Field[] fieldsByPublic = aClass.getFields();
for (Field field : fieldsByPublic) {
System.out.println(field);
}
// 获取全部成员变量公有+私有
Field[] fields = aClass.getDeclaredFields();
for (Field field : fields) {
System.out.println(field);
}
// 成员变量赋值和获取
nameByDeclared.set(object,"tians");
ageByDeclared.setAccessible(true);
ageByDeclared.set(object,999);
System.out.println(nameByDeclared.get(object)+":"+ageByDeclared.get(object));
// 获取指定public方法
Method methodByPub = aClass.getMethod("method1");
System.out.println("获取指定public方法"+methodByPub);
// 获取指定private方法
Method methodByPri = aClass.getDeclaredMethod("printString",String.class);
System.out.println("获取指定private方法"+methodByPri);
// 获取所有public方法
Method[] methodByAllPub = aClass.getMethods();
for (Method method : methodByAllPub) {
System.out.println("获取所有public方法"+method);
}
// 获取所有方法public+private
Method[] methodByAll = aClass.getDeclaredMethods();
for (Method method : methodByAll) {
System.out.println("获取所有方法public+private"+method);
}
// 获取方法并执行
methodByPub.invoke(object);
methodByPri.setAccessible(true);
methodByPri.invoke(object,"2024年1月15日18:09:04");
for (Method method : methodByAll) {
// 反射设置每个方法的访问权限
method.setAccessible(true);
// 判断方法上是否有注解
if (method.isAnnotationPresent(MyTest.class)) {
method.invoke(object);
}
}
//
}
/**
* 获取字节码文件对象(三种方式)
* @return
* @throws Exception
*/
private static Class<?> getClassObject() throws Exception {
Class<?> aClass = Class.forName("com.tians.annotation.MyTestMethod"); // 全类名获取
System.out.println(aClass);
Class<MyTestMethod> aClassByClass = MyTestMethod.class; // 通过class属性获取
System.out.println(aClassByClass);
Class<? extends MyTestMethod> aClassByObjectClass = new MyTestMethod().getClass(); // 通过对象的class属性获取
System.out.println(aClassByObjectClass);
return aClass;
}
}
package com.tians.annotation;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @date : 2024/1/15 9:51
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class MyTestMethod {
public String name;
private Integer age;
@Override
public String toString() {
return "MyTestMethod{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
private void printString(String str) {
System.out.println(name+":"+age+":"+str);
}
public MyTestMethod(String name) {
this.name = name;
}
private MyTestMethod(Integer age ) {
this.age = age;
}
@MyTest
public void method1 () {
System.out.println("method1");
}
public void method2 () {
System.out.println("method2");
}
@MyTest
public void method3 () {
System.out.println("method3");
}
}