16.Java反射

#16. Java反射

一、项目准备与环境搭建

1. 创建Maven项目

  1. 打开IntelliJ IDEA → FileNewProject…
  2. 选择Maven
  3. 填写项目信息:
    • GroupId: com.reflection.demo
    • ArtifactId: java-reflection-tutorial
    • Version: 1.0-SNAPSHOT
  4. 点击Finish

2. 项目结构说明

java-reflection-tutorial/
├── pom.xml                # Maven配置文件
└── src/
    ├── main/
    │   └── java/
    │       └── com/reflection/demo/  # 源代码目录
    │           ├── Main.java          # 主程序入口
    │           └── Person.java        # 反射操作的目标类
    └── test/

二、反射基础概念与目标类

1. 创建反射操作的目标类 Person.java

package com.reflection.demo;

/**
 * 反射操作的目标类
 * 包含:
 * 1. 私有字段和公有字段
 * 2. 私有方法和公有方法
 * 3. 构造方法
 */
public class Person {
    // 私有字段(需要通过反射访问)
    private String secretName;
    
    // 公有字段(可以直接访问)
    public int age;
    
    // 无参构造方法
    public Person() {
        System.out.println("无参构造方法被调用");
    }
    
    // 带参构造方法
    public Person(String name, int age) {
        this.secretName = name;
        this.age = age;
        System.out.println("带参构造方法被调用");
    }
    
    // 公有方法
    public void greet() {
        System.out.println("Hello, my name is " + secretName);
    }
    
    // 私有方法(需要通过反射调用)
    private void printSecret() {
        System.out.println("Secret: My real name is " + secretName + ", age " + age);
    }
    
    // 公有getter方法
    public String getName() {
        return secretName;
    }
    
    // 公有setter方法
    public void setName(String name) {
        this.secretName = name;
    }
    
    @Override //@Override 注解的保留策略是 SOURCE,这意味着它只在源代码级别保留,不会在运行时保留。因此,通过反射无法在运行时获取到 @Override 注解。
    public String toString() {
        return "Person{name='" + secretName + "', age=" + age + "}";
    }
}

在这里插入图片描述

三、反射核心操作详解(Main.java)

package com.reflection.demo;

import java.lang.reflect.*;

/**
 * Java反射机制演示类
 * 包含:
 * 1. 获取Class对象的三种方式
 * 2. 创建对象实例
 * 3. 访问和修改字段
 * 4. 调用方法
 * 5. 获取构造方法
 */
public class Main {
    public static void main(String[] args) {
        try {
            // ==================== 1. 获取Class对象的三种方式 ====================
            System.out.println("=== 1. 获取Class对象的三种方式 ===");
            
            // 方式1:通过类名.class获取(编译时已知)
            Class<?> clazz1 = Person.class;
            System.out.println("方式1获取的Class对象: " + clazz1.getName());
            
            // 方式2:通过对象的getClass()方法获取(运行时已知)
            Person person = new Person();
            Class<?> clazz2 = person.getClass();
            System.out.println("方式2获取的Class对象: " + clazz2.getName());
            
            // 方式3:通过Class.forName()方法获取(通过全限定类名)
            Class<?> clazz3 = Class.forName("com.reflection.demo.Person");
            System.out.println("方式3获取的Class对象: " + clazz3.getName());
            
            // 验证三种方式获取的是同一个Class对象
            System.out.println("clazz1 == clazz2: " + (clazz1 == clazz2));
            System.out.println("clazz1 == clazz3: " + (clazz1 == clazz3));
            
            // ==================== 2. 创建对象实例 ====================
            System.out.println("\n=== 2. 创建对象实例 ===");
            
            // 获取无参构造方法
            Constructor<?> noArgConstructor = clazz3.getDeclaredConstructor();
            // 创建实例
            Object newPerson1 = noArgConstructor.newInstance();
            System.out.println("通过无参构造创建的对象: " + newPerson1);
            
            // 获取带参构造方法
            Constructor<?> paramConstructor = clazz3.getDeclaredConstructor(String.class, int.class);
            // 创建实例
            Object newPerson2 = paramConstructor.newInstance("Alice", 25);
            System.out.println("通过带参构造创建的对象: " + newPerson2);
            
            // ==================== 3. 访问和修改字段 ====================
            System.out.println("\n=== 3. 访问和修改字段 ===");
            
            // 获取私有字段secretName
            Field secretNameField = clazz3.getDeclaredField("secretName");
            // 设置可访问(私有字段需要)
            secretNameField.setAccessible(true);
            
            // 修改字段值
            secretNameField.set(newPerson2, "Bob");
            // 读取字段值
            String name = (String) secretNameField.get(newPerson2);
            System.out.println("修改后的name字段值: " + name);
            
            // 获取公有字段age
            Field ageField = clazz3.getField("age");
            // 修改字段值
            ageField.set(newPerson2, 30);
            // 读取字段值
            int age = ageField.getInt(newPerson2);
            System.out.println("修改后的age字段值: " + age);
            
            // ==================== 4. 调用方法 ====================
            System.out.println("\n=== 4. 调用方法 ===");
            
            // 调用公有方法greet()
            Method greetMethod = clazz3.getMethod("greet");
            greetMethod.invoke(newPerson2);
            
            // 调用公有方法setName()
            Method setNameMethod = clazz3.getMethod("setName", String.class);
            setNameMethod.invoke(newPerson2, "Charlie");
            
            // 调用公有方法getName()
            Method getNameMethod = clazz3.getMethod("getName");
            String currentName = (String) getNameMethod.invoke(newPerson2);
            System.out.println("当前name: " + currentName);
            
            // 调用私有方法printSecret()
            Method printSecretMethod = clazz3.getDeclaredMethod("printSecret");
            printSecretMethod.setAccessible(true);  // 允许访问私有方法
            printSecretMethod.invoke(newPerson2);
            
            // ==================== 5. 获取构造方法 ====================
            System.out.println("\n=== 5. 获取构造方法 ===");
            
            // 获取所有构造方法
            Constructor<?>[] constructors = clazz3.getDeclaredConstructors();
            System.out.println("类 " + clazz3.getName() + " 的构造方法:");
            for (Constructor<?> constructor : constructors) {
                System.out.println("  " + constructor);
            }
            
            // 创建另一个实例
            Constructor<?> anotherConstructor = clazz3.getConstructor(String.class, int.class);
            Person anotherPerson = (Person) anotherConstructor.newInstance("David", 35);
            System.out.println("通过另一个构造方法创建的对象: " + anotherPerson);
            
        } catch (ClassNotFoundException e) {
            System.err.println("未找到类: " + e.getMessage());
        } catch (NoSuchMethodException e) {
            System.err.println("未找到方法: " + e.getMessage());
        } catch (InstantiationException e) {
            System.err.println("无法实例化类: " + e.getMessage());
        } catch (IllegalAccessException e) {
            System.err.println("非法访问: " + e.getMessage());
        } catch (InvocationTargetException e) {
            System.err.println("方法调用异常: " + e.getMessage());
        } catch (NoSuchFieldException e) {
            System.err.println("未找到字段: " + e.getMessage());
        }
    }
}

四、运行与调试

1. 运行项目

  • 右键Main.javaRun ‘Main.main()’
  • 或点击IDEA右上角的绿色运行按钮
    在这里插入图片描述
    运行输出结果:
"C:\Program Files\Java\jdk1.8.0_202\bin\java.exe" "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA Community Edition 2021.2.2\lib\idea_rt.jar=51618:C:\Program Files\JetBrains\IntelliJ IDEA Community Edition 2021.2.2\bin" -Dfile.encoding=UTF-8 -classpath "C:\Program Files\Java\jdk1.8.0_202\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.8.0_202\jre\lib\deploy.jar;C:\Program Files\Java\jdk1.8.0_202\jre\lib\ext\access-bridge-64.jar;C:\Program Files\Java\jdk1.8.0_202\jre\lib\ext\cldrdata.jar;C:\Program Files\Java\jdk1.8.0_202\jre\lib\ext\dnsns.jar;C:\Program Files\Java\jdk1.8.0_202\jre\lib\ext\jaccess.jar;C:\Program Files\Java\jdk1.8.0_202\jre\lib\ext\jfxrt.jar;C:\Program Files\Java\jdk1.8.0_202\jre\lib\ext\localedata.jar;C:\Program Files\Java\jdk1.8.0_202\jre\lib\ext\nashorn.jar;C:\Program Files\Java\jdk1.8.0_202\jre\lib\ext\sunec.jar;C:\Program Files\Java\jdk1.8.0_202\jre\lib\ext\sunjce_provider.jar;C:\Program Files\Java\jdk1.8.0_202\jre\lib\ext\sunmscapi.jar;C:\Program Files\Java\jdk1.8.0_202\jre\lib\ext\sunpkcs11.jar;C:\Program Files\Java\jdk1.8.0_202\jre\lib\ext\zipfs.jar;C:\Program Files\Java\jdk1.8.0_202\jre\lib\javaws.jar;C:\Program Files\Java\jdk1.8.0_202\jre\lib\jce.jar;C:\Program Files\Java\jdk1.8.0_202\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.8.0_202\jre\lib\jfxswt.jar;C:\Program Files\Java\jdk1.8.0_202\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.8.0_202\jre\lib\management-agent.jar;C:\Program Files\Java\jdk1.8.0_202\jre\lib\plugin.jar;C:\Program Files\Java\jdk1.8.0_202\jre\lib\resources.jar;C:\Program Files\Java\jdk1.8.0_202\jre\lib\rt.jar;C:\Users\lx\IdeaProjects\java-reflection-tutorial\target\classes" com.reflection.demo.Main
=== 1. 获取Class对象的三种方式 ===
方式1获取的Class对象: com.reflection.demo.Person
无参构造方法被调用
方式2获取的Class对象: com.reflection.demo.Person
方式3获取的Class对象: com.reflection.demo.Person
clazz1 == clazz2: true
clazz1 == clazz3: true

=== 2. 创建对象实例 ===
无参构造方法被调用
通过无参构造创建的对象: Person{name='null', age=0}
带参构造方法被调用
通过带参构造创建的对象: Person{name='Alice', age=25}

=== 3. 访问和修改字段 ===
修改后的name字段值: Bob
修改后的age字段值: 30

=== 4. 调用方法 ===
Hello, my name is Bob
当前name: Charlie
Secret: My real name is Charlie, age 30

=== 5. 获取构造方法 ===
类 com.reflection.demo.Person 的构造方法:
  public com.reflection.demo.Person()
  public com.reflection.demo.Person(java.lang.String,int)
带参构造方法被调用
通过另一个构造方法创建的对象: Person{name='David', age=35}

Process finished with exit code 0

2. 调试技巧

  1. 在反射调用代码处设置断点
  2. 右键 → Debug运行
  3. Variables视图中:
    • 查看动态创建的对象状态
    • 展开this引用查看内部字段
  4. 使用Evaluate Expression功能:
    • 输入clazz3.getDeclaredFields()查看所有字段
    • 输入secretNameField.getName()查看字段名

五、代码详细注释与知识点讲解

1. 获取Class对象的三种方式

// 方式1:通过类名.class获取(编译时已知)
Class<?> clazz1 = Person.class;
// 方式2:通过对象的getClass()方法获取(运行时已知)
Person person = new Person();
Class<?> clazz2 = person.getClass();
// 方式3:通过Class.forName()方法获取(通过全限定类名)
Class<?> clazz3 = Class.forName("com.reflection.demo.Person");
  • 适用场景
    • 方式1:编译时已知类名(最常用)
    • 方式2:运行时已有对象实例
    • 方式3:通过字符串动态加载类(框架中常见)

2. 创建对象实例

// 获取无参构造方法
Constructor<?> noArgConstructor = clazz3.getDeclaredConstructor();
// 创建实例
Object newPerson1 = noArgConstructor.newInstance();
  • 关键点
    • getDeclaredConstructor():获取所有构造方法(包括私有)
    • newInstance():调用构造方法创建实例

3. 访问和修改字段

// 获取私有字段secretName
Field secretNameField = clazz3.getDeclaredField("secretName");
// 设置可访问(私有字段需要)
secretNameField.setAccessible(true);
// 修改字段值
secretNameField.set(newPerson2, "Bob");
// 读取字段值
String name = (String) secretNameField.get(newPerson2);
  • 关键点
    • getDeclaredField():获取所有字段(包括私有)
    • getField():只能获取公有字段
    • setAccessible(true):绕过Java访问控制检查

4. 调用方法

// 调用公有方法greet()
Method greetMethod = clazz3.getMethod("greet");
greetMethod.invoke(newPerson2);
// 调用私有方法printSecret()
Method printSecretMethod = clazz3.getDeclaredMethod("printSecret");
printSecretMethod.setAccessible(true);  // 允许访问私有方法
printSecretMethod.invoke(newPerson2);
  • 关键点
    • getMethod():获取公有方法
    • getDeclaredMethod():获取所有方法(包括私有)
    • invoke():执行方法

5. 获取构造方法

// 获取所有构造方法
Constructor<?>[] constructors = clazz3.getDeclaredConstructors();
// 创建另一个实例
Constructor<?> anotherConstructor = clazz3.getConstructor(String.class, int.class);
Person anotherPerson = (Person) anotherConstructor.newInstance("David", 35);
  • 关键点
    • getDeclaredConstructors():获取所有构造方法
    • getConstructor():获取公有构造方法

六、常见问题与解决方案

1. ClassNotFoundException

  • 原因:类名拼写错误或类不存在
  • 解决:检查全限定类名是否正确

2. NoSuchMethodException

  • 原因:方法名或参数类型不匹配
  • 解决:检查方法名和参数类型

3. IllegalAccessException

  • 原因:尝试访问私有成员但未设置setAccessible(true)
  • 解决:对私有字段/方法调用setAccessible(true)

4. InstantiationException

  • 原因:尝试实例化抽象类、接口或数组
  • 解决:确保类可以被实例化

七、反射的优缺点

优点

  1. 动态性:可以在运行时检查、修改类结构
  2. 灵活性:可以创建对象、调用方法、访问字段而无需在编译时知道它们的存在
  3. 框架基础:许多框架(如Spring、Hibernate)依赖反射实现核心功能

缺点

  1. 性能开销:反射操作比直接调用慢
  2. 安全限制:需要处理SecurityManager检查
  3. 代码可读性差:反射代码通常难以理解和维护

反射获取Person类所有信息

下面创建一个新的类ClassInfoPrinter,它使用Java反射机制来获取并打印Person类的所有信息,包括字段、方法、构造方法、注解等。
在这里插入图片描述

package com.reflection.demo;

import java.lang.annotation.Annotation;
import java.lang.reflect.*;


/**
 * 使用反射获取并打印类的所有信息
 */
public class ClassInfoPrinter {
    public static void main(String[] args) {
        try {
            // 1. 获取Person类的Class对象
            Class<?> personClass = Class.forName("com.reflection.demo.Person");

            // 2. 打印类基本信息
            System.out.println("=== 类基本信息 ===");
            printClassInfo(personClass);

            // 3. 打印所有字段
            System.out.println("\n=== 字段信息 ===");
            printFieldsInfo(personClass);

            // 4. 打印所有方法
            System.out.println("\n=== 方法信息 ===");
            printMethodsInfo(personClass);

            // 5. 打印所有构造方法
            System.out.println("\n=== 构造方法信息 ===");
            printConstructorsInfo(personClass);

            // 6. 打印类实现的接口
            System.out.println("\n=== 实现的接口 ===");
            printInterfaces(personClass);

            // 7. 打印父类信息
            System.out.println("\n=== 父类信息 ===");
            printSuperClass(personClass);

            // 8. 打印类注解(如果有)
            System.out.println("\n=== 类注解 ===");
            printAnnotations(personClass);

        } catch (ClassNotFoundException e) {
            System.err.println("未找到Person类: " + e.getMessage());
        }
    }

    /**
     * 打印类基本信息
     */
    private static void printClassInfo(Class<?> clazz) {
        System.out.println("类名: " + clazz.getName());
        System.out.println("简单类名: " + clazz.getSimpleName());
        System.out.println("包名: " + clazz.getPackage().getName());
        System.out.println("是否为接口: " + clazz.isInterface());
        System.out.println("是否为枚举: " + clazz.isEnum());
        System.out.println("是否为注解: " + clazz.isAnnotation());
        System.out.println("是否为数组: " + clazz.isArray());
        System.out.println("是否为原始类型: " + clazz.isPrimitive());
        System.out.println("修饰符: " + Modifier.toString(clazz.getModifiers()));
    }

    /**
     * 打印所有字段信息
     */
    private static void printFieldsInfo(Class<?> clazz) {
        // 获取所有字段(包括继承的字段)
        Field[] fields = clazz.getDeclaredFields();

        for (Field field : fields) {
            System.out.println("\n字段名: " + field.getName());
            System.out.println("字段类型: " + field.getType().getName());
            System.out.println("修饰符: " + Modifier.toString(field.getModifiers()));

            // 尝试获取字段的注解(如果有)
            Annotation[] annotations = field.getAnnotations();
            if (annotations.length > 0) {
                System.out.println("注解:");
                for (Annotation annotation : annotations) {
                    System.out.println("  " + annotation);
                }
            } else {
                System.out.println("注解: 无");
            }
        }
    }

    /**
     * 打印所有方法信息
     */
    private static void printMethodsInfo(Class<?> clazz) {
        // 获取所有方法(不包括继承的方法)
        Method[] methods = clazz.getDeclaredMethods();

        for (Method method : methods) {
            System.out.println("\n方法名: " + method.getName());
            System.out.println("返回类型: " + method.getReturnType().getName());

            // 打印参数信息
            System.out.print("参数类型: ");
            Class<?>[] parameterTypes = method.getParameterTypes();
            if (parameterTypes.length == 0) {
                System.out.println("无");
            } else {
                for (Class<?> paramType : parameterTypes) {
                    System.out.print(paramType.getName() + " ");
                }
                System.out.println();
            }

            System.out.println("修饰符: " + Modifier.toString(method.getModifiers()));

            // 打印异常信息
            System.out.print("声明的异常: ");
            Class<?>[] exceptionTypes = method.getExceptionTypes();
            if (exceptionTypes.length == 0) {
                System.out.println("无");
            } else {
                for (Class<?> exceptionType : exceptionTypes) {
                    System.out.print(exceptionType.getName() + " ");
                }
                System.out.println();
            }
        }
    }

    /**
     * 打印所有构造方法信息
     */
    private static void printConstructorsInfo(Class<?> clazz) {
        // 获取所有构造方法
        Constructor<?>[] constructors = clazz.getDeclaredConstructors();

        for (Constructor<?> constructor : constructors) {
            System.out.println("\n构造方法: " + constructor.getName());

            // 打印参数信息
            System.out.print("参数类型: ");
            Class<?>[] parameterTypes = constructor.getParameterTypes();
            if (parameterTypes.length == 0) {
                System.out.println("无");
            } else {
                for (Class<?> paramType : parameterTypes) {
                    System.out.print(paramType.getName() + " ");
                }
                System.out.println();
            }

            System.out.println("修饰符: " + Modifier.toString(constructor.getModifiers()));

            // 打印异常信息
            System.out.print("声明的异常: ");
            Class<?>[] exceptionTypes = constructor.getExceptionTypes();
            if (exceptionTypes.length == 0) {
                System.out.println("无");
            } else {
                for (Class<?> exceptionType : exceptionTypes) {
                    System.out.print(exceptionType.getName() + " ");
                }
                System.out.println();
            }
        }
    }

    /**
     * 打印实现的接口
     */
    private static void printInterfaces(Class<?> clazz) {
        Class<?>[] interfaces = clazz.getInterfaces();
        if (interfaces.length == 0) {
            System.out.println("未实现任何接口");
        } else {
            for (Class<?> iface : interfaces) {
                System.out.println("接口: " + iface.getName());
            }
        }
    }

    /**
     * 打印父类信息
     */
    private static void printSuperClass(Class<?> clazz) {
        Class<?> superClass = clazz.getSuperclass();
        if (superClass == null) {
            System.out.println("没有父类(Object类)");
        } else {
            System.out.println("父类: " + superClass.getName());
        }
    }

    /**
     * 打印类注解
     */
    private static void printAnnotations(Class<?> clazz) {
        // 获取类上的注解
        Annotation[] classAnnotations = clazz.getAnnotations();
        if (classAnnotations.length == 0) {
            System.out.println("无类注解");
        } else {
            System.out.println("类注解:");
            for (Annotation annotation : classAnnotations) {
                System.out.println("  " + annotation);
            }
        }

        // 获取方法上的注解
        System.out.println("\n方法注解:");
        Method[] methods = clazz.getDeclaredMethods();
        if (methods.length == 0) {
            System.out.println("无方法");
        } else {
            for (Method method : methods) {
                Annotation[] methodAnnotations = method.getAnnotations();
                if (methodAnnotations.length == 0) {
                    System.out.println("方法 " + method.getName() + ": 无注解");
                } else {
                    System.out.println("方法 " + method.getName() + " 的注解:");
                    for (Annotation annotation : methodAnnotations) {
                        System.out.println("  " + annotation);
                    }
                }
            }
        }
    }
}

代码说明

  1. 获取Class对象

    • 使用Class.forName()动态加载Person类
  2. 打印类基本信息

    • 类名、简单类名、包名
    • 类类型(接口、枚举、注解、数组等)
    • 修饰符(public、final等)
  3. 字段信息

    • 字段名、类型
    • 修饰符和注解
  4. 方法信息

    • 方法名、返回类型
    • 参数列表和异常声明
  5. 构造方法信息

    • 参数列表和异常声明
  6. 接口和父类信息

    • 实现的接口和继承的父类
  7. 注解信息

    • 类上的注解(虽然Person类没有注解,但展示了如何获取)

运行结果

运行ClassInfoPrinter后,看到以下输出:

"C:\Program Files\Java\jdk1.8.0_202\bin\java.exe" "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA Community Edition 2021.2.2\lib\idea_rt.jar=64236:C:\Program Files\JetBrains\IntelliJ IDEA Community Edition 2021.2.2\bin" -Dfile.encoding=UTF-8 -classpath "C:\Program Files\Java\jdk1.8.0_202\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.8.0_202\jre\lib\deploy.jar;C:\Program Files\Java\jdk1.8.0_202\jre\lib\ext\access-bridge-64.jar;C:\Program Files\Java\jdk1.8.0_202\jre\lib\ext\cldrdata.jar;C:\Program Files\Java\jdk1.8.0_202\jre\lib\ext\dnsns.jar;C:\Program Files\Java\jdk1.8.0_202\jre\lib\ext\jaccess.jar;C:\Program Files\Java\jdk1.8.0_202\jre\lib\ext\jfxrt.jar;C:\Program Files\Java\jdk1.8.0_202\jre\lib\ext\localedata.jar;C:\Program Files\Java\jdk1.8.0_202\jre\lib\ext\nashorn.jar;C:\Program Files\Java\jdk1.8.0_202\jre\lib\ext\sunec.jar;C:\Program Files\Java\jdk1.8.0_202\jre\lib\ext\sunjce_provider.jar;C:\Program Files\Java\jdk1.8.0_202\jre\lib\ext\sunmscapi.jar;C:\Program Files\Java\jdk1.8.0_202\jre\lib\ext\sunpkcs11.jar;C:\Program Files\Java\jdk1.8.0_202\jre\lib\ext\zipfs.jar;C:\Program Files\Java\jdk1.8.0_202\jre\lib\javaws.jar;C:\Program Files\Java\jdk1.8.0_202\jre\lib\jce.jar;C:\Program Files\Java\jdk1.8.0_202\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.8.0_202\jre\lib\jfxswt.jar;C:\Program Files\Java\jdk1.8.0_202\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.8.0_202\jre\lib\management-agent.jar;C:\Program Files\Java\jdk1.8.0_202\jre\lib\plugin.jar;C:\Program Files\Java\jdk1.8.0_202\jre\lib\resources.jar;C:\Program Files\Java\jdk1.8.0_202\jre\lib\rt.jar;C:\Users\lx\IdeaProjects\java-reflection-tutorial\target\classes" com.reflection.demo.ClassInfoPrinter
=== 类基本信息 ===
类名: com.reflection.demo.Person
简单类名: Person
包名: com.reflection.demo
是否为接口: false
是否为枚举: false
是否为注解: false
是否为数组: false
是否为原始类型: false
修饰符: public

=== 字段信息 ===

字段名: secretName
字段类型: java.lang.String
修饰符: private
注解: 无

字段名: age
字段类型: int
修饰符: public
注解: 无

=== 方法信息 ===

方法名: toString
返回类型: java.lang.String
参数类型: 无
修饰符: public
声明的异常: 无

方法名: getName
返回类型: java.lang.String
参数类型: 无
修饰符: public
声明的异常: 无

方法名: setName
返回类型: void
参数类型: java.lang.String 
修饰符: public
声明的异常: 无

方法名: greet
返回类型: void
参数类型: 无
修饰符: public
声明的异常: 无

方法名: printSecret
返回类型: void
参数类型: 无
修饰符: private
声明的异常: 无

=== 构造方法信息 ===

构造方法: com.reflection.demo.Person
参数类型: 无
修饰符: public
声明的异常: 无

构造方法: com.reflection.demo.Person
参数类型: java.lang.String int 
修饰符: public
声明的异常: 无

=== 实现的接口 ===
未实现任何接口

=== 父类信息 ===
父类: java.lang.Object

=== 类注解 ===
无类注解

方法注解:
方法 toString: 无注解
方法 getName: 无注解
方法 setName: 无注解
方法 greet: 无注解
方法 printSecret: 无注解

Process finished with exit code 0

@Override 注解的保留策略是 SOURCE,这意味着它只在源代码级别保留,不会在运行时保留。因此,通过反射无法在运行时获取到 @Override 注解。

学习要点

  1. 反射API

    • Class类是反射的入口
    • getDeclaredFields()/getDeclaredMethods()获取所有成员
    • Modifier类解析修饰符
  2. 动态性

    • 可以在运行时检查类的结构
    • 不需要预先知道类的具体实现
  3. 异常处理

    • 反射操作可能抛出多种异常,需要适当处理
  4. 性能考虑

    • 反射操作比直接调用慢,应谨慎使用

继续练习可以尝试:

  • 添加自定义注解到Person类,然后通过反射读取
  • Java动态代理
  • 注解处理器
  • 反射在框架中的应用(如Spring IoC容器)
  • 实现一个简单的对象序列化/反序列化工具
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值