Java反射与动态代理学习笔记

发布于:2025-09-09 ⋅ 阅读:(22) ⋅ 点赞:(0)

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); // age

Class fieldType = ageField.getType();
System.out.println(fieldType); // int

int 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); // eat

Class returnType = eatMethod.getReturnType();
System.out.println(returnType); // class java.lang.String

Class[] 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; }
    
    @Override
    public 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;
    }
    
    // 唱歌
    @Override
    public String sing() {
        System.out.println(name + "正在唱歌");
        return "谢谢";
    }
    
    // 跳舞
    @Override
    public 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() {
                @Override
                public 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编程、日志记录、事务管理等场景。


网站公告

今日签到

点亮在社区的每一天
去签到