1616 字
8 分钟
Java反射
2025-03-14

Java反射是Java语言的一个重要特性,它允许程序在运行时获取任意类的内部信息,并可以操作这些信息。这种机制使得Java具有了动态获取类信息以及动态调用对象方法的能力。

反射的基本概念#

反射(Reflection)是Java被视为动态(或准动态)语言的一个关键性质。这个机制允许程序在运行时透过类名来获取任意一个类的内部信息,包括成员变量、构造方法、成员方法等,并可以操作这些成员。

反射的主要用途#

  • 动态加载类:在运行时根据需要加载类。
  • 动态创建对象:通过反射来创建对象,无需知道具体的类名。
  • 访问和修改私有成员:可以访问和修改类的私有成员变量和方法。
  • 获取类型信息:在运行时获取类的类型信息。

反射的核心类#

Java反射主要涉及以下核心类:

  • Class:代表一个类或接口的类型信息。
  • Field:代表类的成员变量(字段)。
  • Method:代表类的方法。
  • Constructor:代表类的构造方法。

获取Class对象#

获取Class对象有三种方式:

  • 通过对象获取Class clazz = obj.getClass();
  • 通过类名获取Class clazz = ClassName.class;
  • 通过全限定类名获取Class clazz = Class.forName("com.example.ClassName");

使用反射操作类#

获取成员变量#

Field field = clazz.getDeclaredField("fieldName"); // 获取私有成员变量
field.setAccessible(true); // 取消访问权限检查
Object value = field.get(obj); // 获取成员变量的值
field.set(obj, newValue); // 设置成员变量的值

获取方法#

Method method = clazz.getDeclaredMethod("methodName", paramClass1, paramClass2, ...); // 获取私有方法
// getMthods();会获取包含父类在内的所有方法
method.setAccessible(true); // 取消访问权限检查
Object result = method.invoke(obj, param1, param2, ...); // 调用方法

获取构造方法#

Constructor constructor = clazz.getDeclaredConstructor(paramClass1, paramClass2, ...); // 获取私有构造方法
constructor.setAccessible(true); // 取消访问权限检查
Object instance = constructor.newInstance(param1, param2, ...); // 创建对象

反射的优缺点#

优点

  • 增加程序的灵活性和扩展性。
  • 可以实现动态创建对象和动态调用方法。 缺点
  • 性能开销大:反射操作需要类型检查和解析,因此比直接代码慢。
  • 安全性问题:反射可以访问和修改私有成员,可能会破坏封装性。
  • 代码可读性差:使用反射的代码通常难以理解。

反射的使用场景#

  • 框架开发:如Spring、Hibernate等框架大量使用反射来实现依赖注入、对象关系映射等功能。
  • 动态代理:如AOP(面向切面编程)中使用的动态代理。
  • 编译时无法确定类型的场景。

注意事项#

  • 反射会破坏类的封装性,应谨慎使用。
  • 反射操作可能会抛出ClassNotFoundExceptionNoSuchFieldExceptionNoSuchMethodExceptionIllegalAccessExceptionInvocationTargetException等异常,需要进行异常处理。

反射与泛型的关系#

Java 5引入了泛型,但泛型信息在运行时会被擦除,即所谓的类型擦除。然而,可以通过反射获取到泛型的类型信息,这通常用于框架开发中。

反射的性能优化#

  • 尽量缓存ClassFieldMethodConstructor等反射对象。
  • 减少反射的使用,只在必要的时候使用。
  • 使用setAccessible(true)来提高访问私有成员的速度。 通过以上讲解,相信您对Java反射有了更深入的理解。反射是Java中一个非常强大的工具,但使用时需要谨慎,以避免带来不必要的性能问题和安全问题。

示例1:获取Class对象#

public class ReflectionExample {
    public static void main(String[] args) {
        // 通过对象获取Class对象
        Person person = new Person();
        Class<?> clazz1 = person.getClass();
        // 通过类名获取Class对象
        Class<?> clazz2 = Person.class;
        // 通过全限定类名获取Class对象
        try {
            Class<?> clazz3 = Class.forName("com.example.Person");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        System.out.println(clazz1 == clazz2); // 输出true,表示是同一个Class对象
    }
}
class Person {
    // Person类的定义
}

示例2:创建对象#

public class ReflectionCreateObject {
    public static void main(String[] args) {
        try {
            Class<?> clazz = Class.forName("com.example.Person");
            // 调用无参构造方法创建对象
            Person person = (Person) clazz.newInstance();
        } catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {
            e.printStackTrace();
        }
    }
}
class Person {
    public Person() {
        // 无参构造方法
    }
}

示例3:访问和修改字段#

public class ReflectionFieldAccess {
    public static void main(String[] args) {
        try {
            Class<?> clazz = Class.forName("com.example.Person");
            Person person = (Person) clazz.newInstance();
            // 获取字段
            Field nameField = clazz.getDeclaredField("name");
            // 设置可访问性
            nameField.setAccessible(true);
            // 修改字段值
            nameField.set(person, "Alice");
            // 获取字段值
            String name = (String) nameField.get(person);
            System.out.println(name); // 输出Alice
        } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | NoSuchFieldException e) {
            e.printStackTrace();
        }
    }
}
class Person {
    private String name;
    public Person() {
        this.name = "Unknown";
    }
}

示例4:调用方法#

public class ReflectionMethodInvoke {
    public static void main(String[] args) {
        try {
            Class<?> clazz = Class.forName("com.example.Person");
            Person person = (Person) clazz.newInstance();
            // 获取方法
            Method sayHelloMethod = clazz.getDeclaredMethod("sayHello", String.class);
            // 设置可访问性
            sayHelloMethod.setAccessible(true);
            // 调用方法
            sayHelloMethod.invoke(person, "Bob");
        } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | NoSuchMethodException | InvocationTargetException e) {
            e.printStackTrace();
        }
    }
}
class Person {
    public void sayHello(String name) {
        System.out.println("Hello, " + name);
    }
}

示例5:获取构造方法并创建对象#

public class ReflectionConstructor {
    public static void main(String[] args) {
        try {
            Class<?> clazz = Class.forName("com.example.Person");
            // 获取有参构造方法
            Constructor<?> constructor = clazz.getConstructor(String.class, int.class);
            // 创建对象
            Person person = (Person) constructor.newInstance("Charlie", 30);
        } catch (ClassNotFoundException | NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException e) {
            e.printStackTrace();
        }
    }
}
class Person {
    private String name;
    private int age;
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
}

示例6: 获取类所有的方法#

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Parameter;
import java.lang.reflect.Type;

public class ReflectionAPITable {

    public static void printAPITable(Object obj) {
        Class<?> clazz = obj.getClass();
        Method[] methods = clazz.getMethods(); // 获取所有公共方法

        // 打印表头
        System.out.printf("%-20s %-50s %-20s %-10s%n", "方法名称", "参数列表", "返回类型", "修饰符");

        // 遍历所有方法
        for (Method method : methods) {
            // 获取方法名称
            String methodName = method.getName();

            // 获取参数类型
            Parameter[] parameters = method.getParameters();
            StringBuilder paramsBuilder = new StringBuilder();
            for (Parameter parameter : parameters) {
                if (paramsBuilder.length() > 0) paramsBuilder.append(", ");
                paramsBuilder.append(parameter.getType().getSimpleName()).append(" ").append(parameter.getName());
            }
            String params = paramsBuilder.toString();

            // 获取返回类型
            Type returnType = method.getGenericReturnType();
            String returnTypeName = returnType.getTypeName();

            // 获取修饰符
            String modifiers = Modifier.toString(method.getModifiers());

            // 打印方法信息
            System.out.printf("%-20s %-50s %-20s %-10s%n", methodName, params, returnTypeName, modifiers);
        }
    }

    public static void main(String[] args) {
        // 示例对象
        Person person = new Person("Alice", 30);

        // 打印API表格
        printAPITable(person);
    }
}

class Person {
    private String name;
    private int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    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 void sayHello() {
        System.out.println("Hello, my name is " + name);
    }
}
Java反射
http://zaoweiceng.github.io/posts/java/反射/
作者
静惜
发布于
2025-03-14
许可协议
CC BY-NC-SA 4.0