Java反射详解

一、反射基础概念

1.1 什么是反射?

反射(Reflection)是Java语言的一种特性,允许程序在运行时获取类的内部信息,并能直接操作类的属性、方法和构造函数。

通俗理解:就像给Java程序装了一面"镜子",可以照出类的所有内部结构,即使这些结构在编译时是私有的或不可见的。

1.2 反射的核心类

  • Class - 代表类的实体
  • Field - 代表类的成员变量
  • Method - 代表类的方法
  • Constructor - 代表类的构造方法

二、获取Class对象的三种方式

public class ClassObjectExample {
    public static void main(String[] args) throws Exception {
        // 方式1:通过类名.class
        Class<String> stringClass = String.class;
        System.out.println("方式1: " + stringClass.getName());
        
        // 方式2:通过对象.getClass()
        String str = "Hello";
        Class<?> strClass = str.getClass();
        System.out.println("方式2: " + strClass.getName());
        
        // 方式3:通过Class.forName()
        Class<?> forNameClass = Class.forName("java.lang.String");
        System.out.println("方式3: " + forNameClass.getName());
        
        // 验证三个Class对象是否相同
        System.out.println("是否相同: " + (stringClass == strClass && strClass == forNameClass));
    }
}

三、反射操作构造函数

import java.lang.reflect.Constructor;

public class ConstructorExample {
    static class User {
        private String name;
        private int age;
        
        public User() {
            this.name = "默认用户";
            this.age = 18;
        }
        
        public User(String name) {
            this.name = name;
            this.age = 20;
        }
        
        private User(String name, int age) {
            this.name = name;
            this.age = age;
        }
        
        @Override
        public String toString() {
            return "User{name='" + name + "', age=" + age + "}";
        }
    }
    
    public static void main(String[] args) throws Exception {
        Class<User> userClass = User.class;
        
        // 1. 获取所有公有构造方法
        System.out.println("=== 公有构造方法 ===");
        Constructor<?>[] publicConstructors = userClass.getConstructors();
        for (Constructor<?> constructor : publicConstructors) {
            System.out.println(constructor);
        }
        
        // 2. 获取所有构造方法(包括私有)
        System.out.println("\n=== 所有构造方法 ===");
        Constructor<?>[] allConstructors = userClass.getDeclaredConstructors();
        for (Constructor<?> constructor : allConstructors) {
            System.out.println(constructor);
        }
        
        // 3. 调用无参构造创建对象
        System.out.println("\n=== 调用无参构造 ===");
        Constructor<User> noArgConstructor = userClass.getConstructor();
        User user1 = noArgConstructor.newInstance();
        System.out.println(user1);
        
        // 4. 调用有参构造创建对象
        System.out.println("\n=== 调用有参构造 ===");
        Constructor<User> oneArgConstructor = userClass.getConstructor(String.class);
        User user2 = oneArgConstructor.newInstance("张三");
        System.out.println(user2);
        
        // 5. 调用私有构造方法
        System.out.println("\n=== 调用私有构造 ===");
        Constructor<User> privateConstructor = userClass.getDeclaredConstructor(String.class, int.class);
        privateConstructor.setAccessible(true); // 设置可访问私有方法
        User user3 = privateConstructor.newInstance("李四", 25);
        System.out.println(user3);
    }
}

四、反射操作字段(Field)

import java.lang.reflect.Field;

public class FieldExample {
    static class Student {
        public String publicField = "公有字段";
        protected String protectedField = "受保护字段";
        private String privateField = "私有字段";
        String defaultField = "默认字段";
    }
    
    public static void main(String[] args) throws Exception {
        Class<Student> studentClass = Student.class;
        Student student = studentClass.newInstance();
        
        // 1. 获取所有公有字段
        System.out.println("=== 公有字段 ===");
        Field[] publicFields = studentClass.getFields();
        for (Field field : publicFields) {
            System.out.println(field.getName() + ": " + field.get(student));
        }
        
        // 2. 获取所有字段(包括私有)
        System.out.println("\n=== 所有字段 ===");
        Field[] allFields = studentClass.getDeclaredFields();
        for (Field field : allFields) {
            field.setAccessible(true); // 设置可访问私有字段
            System.out.println(field.getName() + ": " + field.get(student));
        }
        
        // 3. 获取特定字段并修改值
        System.out.println("\n=== 修改字段值 ===");
        Field privateField = studentClass.getDeclaredField("privateField");
        privateField.setAccessible(true);
        System.out.println("修改前: " + privateField.get(student));
        privateField.set(student, "修改后的私有字段");
        System.out.println("修改后: " + privateField.get(student));
        
        // 4. 获取和修改静态字段
        System.out.println("\n=== 静态字段操作 ===");
        Field staticField = FieldExample.class.getDeclaredField("STATIC_FIELD");
        System.out.println("静态字段: " + staticField.get(null));
        staticField.set(null, "修改后的静态字段");
        System.out.println("修改后: " + staticField.get(null));
    }
    
    public static String STATIC_FIELD = "原始静态字段";
}

五、反射操作方法(Method)

import java.lang.reflect.Method;

public class MethodExample {
    static class Calculator {
        public int add(int a, int b) {
            return a + b;
        }
        
        protected int multiply(int a, int b) {
            return a * b;
        }
        
        private int subtract(int a, int b) {
            return a - b;
        }
        
        public static void staticMethod() {
            System.out.println("这是一个静态方法");
        }
        
        private void printMessage(String message) {
            System.out.println("消息: " + message);
        }
    }
    
    public static void main(String[] args) throws Exception {
        Class<Calculator> calculatorClass = Calculator.class;
        Calculator calculator = calculatorClass.newInstance();
        
        // 1. 获取所有公有方法(包括继承的)
        System.out.println("=== 公有方法 ===");
        Method[] publicMethods = calculatorClass.getMethods();
        for (Method method : publicMethods) {
            System.out.println(method.getName());
        }
        
        // 2. 获取本类所有方法(包括私有)
        System.out.println("\n=== 本类所有方法 ===");
        Method[] allMethods = calculatorClass.getDeclaredMethods();
        for (Method method : allMethods) {
            System.out.println(method.getName());
        }
        
        // 3. 调用公有方法
        System.out.println("\n=== 调用公有方法 ===");
        Method addMethod = calculatorClass.getMethod("add", int.class, int.class);
        int result = (int) addMethod.invoke(calculator, 10, 20);
        System.out.println("10 + 20 = " + result);
        
        // 4. 调用私有方法
        System.out.println("\n=== 调用私有方法 ===");
        Method subtractMethod = calculatorClass.getDeclaredMethod("subtract", int.class, int.class);
        subtractMethod.setAccessible(true);
        int subtractResult = (int) subtractMethod.invoke(calculator, 20, 10);
        System.out.println("20 - 10 = " + subtractResult);
        
        // 5. 调用静态方法
        System.out.println("\n=== 调用静态方法 ===");
        Method staticMethod = calculatorClass.getDeclaredMethod("staticMethod");
        staticMethod.invoke(null);
        
        // 6. 调用带参数的方法
        System.out.println("\n=== 调用带参方法 ===");
        Method printMethod = calculatorClass.getDeclaredMethod("printMessage", String.class);
        printMethod.setAccessible(true);
        printMethod.invoke(calculator, "Hello Reflection!");
    }
}

六、反射操作数组

import java.lang.reflect.Array;

public class ArrayReflectionExample {
    public static void main(String[] args) throws Exception {
        // 1. 创建数组
        System.out.println("=== 创建数组 ===");
        int[] intArray = (int[]) Array.newInstance(int.class, 5);
        System.out.println("数组长度: " + Array.getLength(intArray));
        
        // 2. 设置数组元素
        System.out.println("\n=== 设置数组元素 ===");
        for (int i = 0; i < Array.getLength(intArray); i++) {
            Array.set(intArray, i, i * 10);
        }
        
        // 3. 获取数组元素
        System.out.println("\n=== 获取数组元素 ===");
        for (int i = 0; i < Array.getLength(intArray); i++) {
            System.out.println("intArray[" + i + "] = " + Array.get(intArray, i));
        }
        
        // 4. 创建多维数组
        System.out.println("\n=== 多维数组 ===");
        int[][] twoDArray = (int[][]) Array.newInstance(int.class, 3, 4);
        
        // 设置多维数组值
        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < 4; j++) {
                Array.set(Array.get(twoDArray, i), j, i * 10 + j);
            }
        }
        
        // 读取多维数组值
        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < 4; j++) {
                System.out.print(Array.get(Array.get(twoDArray, i), j) + "\t");
            }
            System.out.println();
        }
    }
}

七、反射操作注解

import java.lang.annotation.*;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

// 定义注解
@Target({ElementType.TYPE, ElementType.FIELD, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation {
    String value() default "";
    String description() default "";
}

// 使用注解的类
@MyAnnotation(value = "类注解", description = "这是一个测试类")
class AnnotatedClass {
    @MyAnnotation(value = "字段注解", description = "用户名字段")
    private String username;
    
    @MyAnnotation(value = "方法注解", description = "获取用户信息")
    public void getUserInfo() {
        System.out.println("用户信息");
    }
}

public class AnnotationReflectionExample {
    public static void main(String[] args) throws Exception {
        Class<AnnotatedClass> clazz = AnnotatedClass.class;
        
        // 1. 获取类上的注解
        System.out.println("=== 类注解 ===");
        if (clazz.isAnnotationPresent(MyAnnotation.class)) {
            MyAnnotation classAnnotation = clazz.getAnnotation(MyAnnotation.class);
            System.out.println("值: " + classAnnotation.value());
            System.out.println("描述: " + classAnnotation.description());
        }
        
        // 2. 获取字段上的注解
        System.out.println("\n=== 字段注解 ===");
        Field field = clazz.getDeclaredField("username");
        if (field.isAnnotationPresent(MyAnnotation.class)) {
            MyAnnotation fieldAnnotation = field.getAnnotation(MyAnnotation.class);
            System.out.println("值: " + fieldAnnotation.value());
            System.out.println("描述: " + fieldAnnotation.description());
        }
        
        // 3. 获取方法上的注解
        System.out.println("\n=== 方法注解 ===");
        Method method = clazz.getMethod("getUserInfo");
        if (method.isAnnotationPresent(MyAnnotation.class)) {
            MyAnnotation methodAnnotation = method.getAnnotation(MyAnnotation.class);
            System.out.println("值: " + methodAnnotation.value());
            System.out.println("描述: " + methodAnnotation.description());
        }
        
        // 4. 获取所有注解
        System.out.println("\n=== 所有注解 ===");
        Annotation[] annotations = clazz.getAnnotations();
        for (Annotation annotation : annotations) {
            System.out.println(annotation.annotationType().getSimpleName());
        }
    }
}

八、实际生产开发中的使用场景

8.1 Spring框架的依赖注入

// 模拟Spring的依赖注入
public class SimpleContainer {
    private Map<String, Object> beans = new HashMap<>();
    
    public void register(String name, Object bean) {
        beans.put(name, bean);
    }
    
    public <T> T getBean(Class<T> clazz) throws Exception {
        // 创建实例
        T instance = clazz.newInstance();
        
        // 注入依赖(模拟@Autowired)
        Field[] fields = clazz.getDeclaredFields();
        for (Field field : fields) {
            if (beans.containsKey(field.getName())) {
                field.setAccessible(true);
                field.set(instance, beans.get(field.getName()));
            }
        }
        
        return instance;
    }
}

// 使用示例
class UserService {
    private UserRepository userRepository;
    
    public void saveUser(String user) {
        userRepository.save(user);
        System.out.println("保存用户: " + user);
    }
}

class UserRepository {
    public void save(String user) {
        System.out.println("数据库保存: " + user);
    }
}

public class SpringLikeExample {
    public static void main(String[] args) throws Exception {
        SimpleContainer container = new SimpleContainer();
        container.register("userRepository", new UserRepository());
        
        UserService userService = container.getBean(UserService.class);
        userService.saveUser("张三");
    }
}

8.2 JSON序列化/反序列化

import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;

// 简单的JSON序列化工具
public class SimpleJsonSerializer {
    
    // 对象转JSON
    public static String toJson(Object obj) throws Exception {
        Class<?> clazz = obj.getClass();
        Field[] fields = clazz.getDeclaredFields();
        
        StringBuilder json = new StringBuilder();
        json.append("{");
        
        for (int i = 0; i < fields.length; i++) {
            Field field = fields[i];
            field.setAccessible(true);
            
            json.append("\"").append(field.getName()).append("\":");
            
            Object value = field.get(obj);
            if (value instanceof String) {
                json.append("\"").append(value).append("\"");
            } else {
                json.append(value);
            }
            
            if (i < fields.length - 1) {
                json.append(",");
            }
        }
        
        json.append("}");
        return json.toString();
    }
    
    // JSON转对象
    public static <T> T fromJson(String json, Class<T> clazz) throws Exception {
        T instance = clazz.newInstance();
        
        // 简单解析JSON(实际生产环境使用成熟的JSON库)
        json = json.replace("{", "").replace("}", "");
        String[] pairs = json.split(",");
        
        for (String pair : pairs) {
            String[] keyValue = pair.split(":");
            String key = keyValue[0].replace("\"", "").trim();
            String value = keyValue[1].replace("\"", "").trim();
            
            Field field = clazz.getDeclaredField(key);
            field.setAccessible(true);
            
            // 类型转换(简化版)
            if (field.getType() == int.class) {
                field.set(instance, Integer.parseInt(value));
            } else if (field.getType() == String.class) {
                field.set(instance, value);
            }
        }
        
        return instance;
    }
}

// 测试类
class Person {
    private String name;
    private int age;
    private String city;
    
    // 省略getter/setter...
    
    @Override
    public String toString() {
        return "Person{name='" + name + "', age=" + age + ", city='" + city + "'}";
    }
}

public class JsonExample {
    public static void main(String[] args) throws Exception {
        Person person = new Person();
        
        // 使用反射设置字段值
        Class<Person> clazz = Person.class;
        Field nameField = clazz.getDeclaredField("name");
        nameField.setAccessible(true);
        nameField.set(person, "张三");
        
        Field ageField = clazz.getDeclaredField("age");
        ageField.setAccessible(true);
        ageField.set(person, 25);
        
        Field cityField = clazz.getDeclaredField("city");
        cityField.setAccessible(true);
        cityField.set(person, "北京");
        
        // 序列化为JSON
        String json = SimpleJsonSerializer.toJson(person);
        System.out.println("序列化: " + json);
        
        // 反序列化
        Person newPerson = SimpleJsonSerializer.fromJson(json, Person.class);
        System.out.println("反序列化: " + newPerson);
    }
}

8.3 数据库ORM框架

import java.lang.reflect.Field;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;

// 模拟简单的ORM框架
public class SimpleORM {
    
    public static <T> List<T> query(Connection conn, Class<T> clazz, String sql) throws Exception {
        List<T> result = new ArrayList<>();
        
        try (PreparedStatement stmt = conn.prepareStatement(sql);
             ResultSet rs = stmt.executeQuery()) {
            
            ResultSetMetaData metaData = rs.getMetaData();
            int columnCount = metaData.getColumnCount();
            
            while (rs.next()) {
                T obj = clazz.newInstance();
                
                for (int i = 1; i <= columnCount; i++) {
                    String columnName = metaData.getColumnName(i);
                    Object columnValue = rs.getObject(i);
                    
                    // 使用反射设置字段值
                    try {
                        Field field = clazz.getDeclaredField(columnName.toLowerCase());
                        field.setAccessible(true);
                        field.set(obj, columnValue);
                    } catch (NoSuchFieldException e) {
                        // 字段不存在,跳过
                    }
                }
                
                result.add(obj);
            }
        }
        
        return result;
    }
}

// 实体类
class User {
    private int id;
    private String name;
    private String email;
    
    @Override
    public String toString() {
        return "User{id=" + id + ", name='" + name + "', email='" + email + "'}";
    }
}

public class ORMExample {
    public static void main(String[] args) {
        // 实际使用时需要真实的数据库连接
        // 这里只是展示反射在ORM中的应用思路
        System.out.println("ORM框架通常使用反射来实现对象关系映射");
    }
}

九、反射的优缺点

优点:

  1. 灵活性:可以在运行时动态创建对象、调用方法
  2. 扩展性:可以实现插件化架构
  3. 框架开发:是很多框架(Spring、MyBatis等)的基础

缺点:

  1. 性能开销:反射操作比直接调用慢
  2. 安全性问题:可以绕过访问控制检查
  3. 代码复杂度:使代码难以理解和维护
  4. 调试困难:运行时错误难以追踪

十、性能优化建议

public class ReflectionPerformance {
    private static final int LOOP_COUNT = 1000000;
    
    // 普通方法调用
    public static void normalCall() {
        long start = System.currentTimeMillis();
        Example example = new Example();
        for (int i = 0; i < LOOP_COUNT; i++) {
            example.doSomething();
        }
        long end = System.currentTimeMillis();
        System.out.println("普通调用耗时: " + (end - start) + "ms");
    }
    
    // 反射方法调用
    public static void reflectionCall() throws Exception {
        long start = System.currentTimeMillis();
        Example example = new Example();
        Class<?> clazz = example.getClass();
        Method method = clazz.getMethod("doSomething");
        
        for (int i = 0; i < LOOP_COUNT; i++) {
            method.invoke(example);
        }
        long end = System.currentTimeMillis();
        System.out.println("反射调用耗时: " + (end - start) + "ms");
    }
    
    // 优化后的反射调用(缓存Method对象)
    public static void optimizedReflectionCall() throws Exception {
        long start = System.currentTimeMillis();
        Example example = new Example();
        Class<?> clazz = example.getClass();
        Method method = clazz.getMethod("doSomething");
        method.setAccessible(true); // 设置可访问,提高性能
        
        for (int i = 0; i < LOOP_COUNT; i++) {
            method.invoke(example);
        }
        long end = System.currentTimeMillis();
        System.out.println("优化反射调用耗时: " + (end - start) + "ms");
    }
    
    static class Example {
        public void doSomething() {
            // 空方法,用于测试性能
        }
    }
    
    public static void main(String[] args) throws Exception {
        normalCall();
        reflectionCall();
        optimizedReflectionCall();
    }
}

总结

反射是Java中非常强大的特性,它为框架开发、动态代理、测试工具等提供了基础支持。虽然反射有性能开销和安全风险,但在合适的场景下使用可以极大提高代码的灵活性和可扩展性。

使用建议

  • 在框架开发中大量使用
  • 在业务代码中谨慎使用
  • 注意性能优化,缓存反射对象
  • 处理好安全检查异常
posted @ 2025-11-04 14:24  吹吹风喝喝酒  阅读(14)  评论(0)    收藏  举报