Java 反射与动态代理学习笔记
反射概述
反射允许对成员变量、成员方法和构造方法进行编程访问,提供了在运行时分析类和对象的能力。
获取Class对象的三种方式
方式 | 代码示例 | 说明 |
---|
Class.forName() | Class.forName("全类名") | 通过类的全限定名获取Class对象 |
对象.getClass() | 对象.getClass() | 通过对象实例获取Class对象 |
类名.class | 类名.class | 通过类字面常量获取Class对象 |
// 1. Class.forName("全类名")
Class clazz1 = Class.forName("com.zzz.Student");
System.out.println(clazz1);// 2. 对象.getClass()
ReflectionDemo reflectionDemo = new ReflectionDemo();
Class clazz2 = reflectionDemo.getClass();// 3. 类名.class
Class clazz3 = ReflectionDemo.class;// 三种方式获取的Class对象是相同的
System.out.println(clazz1 == clazz2); // true
System.out.println(clazz1 == clazz3); // true
反射操作构造方法
Class类中获取构造方法的方法
方法 | 说明 |
---|
Constructor<?>[] getConstructors() | 返回所有公共构造方法对象的数组 |
Constructor<?>[] getDeclaredConstructors() | 返回所有构造方法对象的数组 |
Constructor<T> getConstructor(Class<?>... parameterTypes) | 返回单个公共构造方法对象 |
Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes) | 返回单个构造方法对象 |
Constructor类中创建对象的方法
方法 | 说明 |
---|
T newInstance(Object... initargs) | 根据指定的构造方法创建对象 |
setAccessible(boolean flag) | 设置为true,表示取消访问检查 |
// 获取所有公共构造方法
Constructor[] constructors = clazz1.getConstructors();
for (Constructor c : constructors) {System.out.println(c);
}
// 输出:
// public com.zzz.Student()
// public com.zzz.Student(java.lang.String,int)// 获取所有构造方法(包括私有和受保护的)
Constructor[] allConstructors = clazz1.getDeclaredConstructors();
for (Constructor c : allConstructors) {System.out.println(c);
}
// 输出:
// public com.zzz.Student()
// private com.zzz.Student(int)
// protected com.zzz.Student(java.lang.String)
// public com.zzz.Student(java.lang.String,int)// 获取特定构造方法
Constructor constructor = clazz1.getConstructor(String.class, int.class);
System.out.println(constructor); // public com.zzz.Student(java.lang.String,int)// 获取私有构造方法
Constructor privateConstructor = clazz1.getDeclaredConstructor(int.class);
System.out.println(privateConstructor);// 使用构造方法创建对象
constructor.setAccessible(true); // 临时取消权限校验
Student stu = (Student) constructor.newInstance("张三", 18);
System.out.println(stu);
反射操作成员变量
Class类中获取成员变量的方法
方法 | 说明 |
---|
Field[] getFields() | 返回所有公共成员变量对象的数组 |
Field[] getDeclaredFields() | 返回所有成员变量对象的数组 |
Field getField(String name) | 返回单个公共成员变量对象 |
Field getDeclaredField(String name) | 返回单个成员变量对象 |
Field类中操作成员变量的方法
方法 | 说明 |
---|
void set(Object obj, Object value) | 给指定对象的字段赋值 |
Object get(Object obj) | 获取指定对象的字段值 |
String getName() | 获取字段名称 |
Class<?> getType() | 获取字段类型 |
int getModifiers() | 获取字段修饰符 |
// 获取所有公共成员变量
Field[] publicFields = clazz1.getFields();
for (Field f : publicFields) {System.out.println(f);
}
// 输出: public java.lang.String com.zzz.Student.gender// 获取所有成员变量(包括私有)
Field[] allFields = clazz1.getDeclaredFields();
for (Field f : allFields) {System.out.println(f);
}
// 输出:
// private java.lang.String com.zzz.Student.name
// private int com.zzz.Student.age
// public java.lang.String com.zzz.Student.gender// 获取特定成员变量
Field ageField = clazz1.getDeclaredField("age");
System.out.println(ageField); // private int com.zzz.Student.age// 获取成员变量信息
String fieldName = ageField.getName();
System.out.println(fieldName); // ageClass fieldType = ageField.getType();
System.out.println(fieldType); // intint modifiers = ageField.getModifiers();
System.out.println(modifiers); // 2 (表示private)// 获取和设置字段值
Student student = new Student("张三", 18, "男");
ageField.setAccessible(true); // 访问私有字段需要取消访问检查
int ageValue = (int) ageField.get(student);
System.out.println(ageValue); // 18// 修改字段值
ageField.set(student, 19);
System.out.println(student); // Student{name='张三', age=19, gender='男'}
反射操作成员方法
Class类中获取成员方法的方法
方法 | 说明 |
---|
Method[] getMethods() | 返回所有公共成员方法对象的数组(包括父类方法) |
Method[] getDeclaredMethods() | 返回所有成员方法对象的数组(仅本类方法) |
Method getMethod(String name, Class<?>... parameterTypes) | 返回单个公共成员方法对象 |
Method getDeclaredMethod(String name, Class<?>... parameterTypes) | 返回单个成员方法对象 |
Method类中调用方法的方法
方法 | 说明 |
---|
Object invoke(Object obj, Object... args) | 调用方法 |
String getName() | 获取方法名称 |
Class<?> getReturnType() | 获取方法返回值类型 |
Class<?>[] getParameterTypes() | 获取方法参数类型数组 |
Class<?>[] getExceptionTypes() | 获取方法异常类型数组 |
int getModifiers() | 获取方法修饰符 |
// 获取所有公共方法(包括父类方法)
Method[] publicMethods = clazz1.getMethods();
for (Method m : publicMethods) {System.out.println(m);
}// 获取所有方法(仅本类方法)
Method[] allMethods = clazz1.getDeclaredMethods();
for (Method m : allMethods) {System.out.println(m);
}// 获取特定方法
Method sleepMethod = clazz1.getMethod("sleep");
System.out.println(sleepMethod);// 获取带参数的方法
Method eatMethod = clazz1.getDeclaredMethod("eat", String.class);
System.out.println(eatMethod);// 获取方法信息
int methodModifiers = eatMethod.getModifiers();
System.out.println(methodModifiers);String methodName = eatMethod.getName();
System.out.println(methodName); // eatClass returnType = eatMethod.getReturnType();
System.out.println(returnType); // class java.lang.StringClass[] parameterTypes = eatMethod.getParameterTypes();
for (Class c : parameterTypes) {System.out.println(c); // class java.lang.String
}Class[] exceptionTypes = eatMethod.getExceptionTypes();
for (Class c : exceptionTypes) {System.out.println(c); // class java.io.IOException, class java.lang.ClassNotFoundException
}// 调用方法
Student student = new Student("张三", 18, "男");
eatMethod.setAccessible(true); // 访问私有方法需要取消访问检查
Object result = eatMethod.invoke(student, "西风");
System.out.println(result); // 吃奥里给
import java.io.IOException;public class Student {private String name;private int age;public String gender;public Student() {}public Student(String name, int age) {this.name = name;this.age = age;}protected Student(String name) {this.name = name;}private Student(int age) {this.age = age;}public Student(String name, int age, String gender) {this.name = name;this.age = age;this.gender = gender;}// Getter和Setter方法public String getName() { return name; }public void setName(String name) { this.name = name; }public int getAge() { return age; }public void setAge(int age) { this.age = age; }public String getGender() { return gender; }public void setGender(String gender) { this.gender = gender; }@Overridepublic String toString() {return "Student{name='" + name + "', age=" + age + ", gender='" + gender + "'}";}public void sleep() {System.out.println("睡觉");}private String eat(String something) throws IOException, ClassNotFoundException {System.out.println("吃" + something);return "吃奥里给";}
}
反射与配置文件结合
利用反射与配置文件结合的方式,可以动态创建对象并调用方法,提高代码的灵活性。
import java.io.FileInputStream;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Properties;public class Test {public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {// 1. 读取配置文件Properties properties = new Properties();FileInputStream fis = new FileInputStream("day27-Reflection\\src\\prop.properties");properties.load(fis);fis.close();System.out.println(properties);// 2. 获取全类名和方法名String methodName = properties.getProperty("method");String className = properties.getProperty("className");System.out.println(className);System.out.println(methodName);// 3. 利用反射创建对象Class clazz = Class.forName(className);Constructor constructor = clazz.getConstructor();Object obj = constructor.newInstance();System.out.println(obj);// 4. 获取并调用方法Method method = clazz.getDeclaredMethod(methodName);method.setAccessible(true);method.invoke(obj);}
}
配置文件示例(prop.properties):
className=com.zzz.demo.Student
method=study




动态代理
动态代理可以在运行时创建代理对象,对方法调用进行拦截和处理。
代理接口
public interface Star {// 唱歌String sing();// 跳舞void dance();
}
被代理类
public class BigStar implements Star {private String name;public BigStar() {}public BigStar(String name) {this.name = name;}// 唱歌@Overridepublic String sing() {System.out.println(name + "正在唱歌");return "谢谢";}// 跳舞@Overridepublic void dance() {System.out.println(name + "正在跳舞");}// Getter和Setter省略
}
代理工具类
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;public class ProxyUtil {/*** JDK创建代理对象* Java.lang.reflect.Proxy类中提供了为对象产生代理对象的方法* * public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)* 参数一:用于指定用哪个类加载器,去加载生成的代理类* 参数二:指定接口,这些接口用于指定生成的代理有哪些方法* 参数三:用来指定生成的代理对象要干什么事*/public static Star createProxy(BigStar bigStar) {Star star = (Star) Proxy.newProxyInstance(ProxyUtil.class.getClassLoader(),new Class[]{Star.class},new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {/*** proxy 第一个参数:代理的对象* method 第二个参数:代理对象要调用的方法 sing* args 第三个参数:代理对象要调用方法时,传递的参数*/if (method.getName().equals("sing")) {System.out.println("代理开始工作,准备话筒,收钱");} else if (method.getName().equals("dance")) {System.out.println("代理开始工作,准备场地,收钱");}// 调用大明星中的唱歌或者跳舞方法Object result = method.invoke(bigStar, args);if (method.getName().equals("sing")) {System.out.println("代理工作结束(唱歌)");} else if (method.getName().equals("dance")) {System.out.println("代理工作结束(跳舞)");}return result;}});return star;}
}
测试代理
public class Test {public static void main(String[] args) {BigStar star = new BigStar("张三");Star proxy = ProxyUtil.createProxy(star);proxy.dance();// 输出:// 代理开始工作,准备场地,收钱// 张三正在跳舞// 代理工作结束(跳舞)String singResult = proxy.sing();System.out.println(singResult);// 输出:// 代理开始工作,准备话筒,收钱// 张三正在唱歌// 代理工作结束(唱歌)// 谢谢}
}
总结
反射是Java中强大的特性,它允许程序在运行时检查类、接口、字段和方法的信息,并能够动态创建对象、调用方法和访问字段。结合配置文件使用反射可以提高代码的灵活性和可扩展性。
动态代理则基于反射机制,允许在运行时创建代理对象,对方法调用进行拦截和处理,常用于AOP编程、日志记录、事务管理等场景。