JAVA作业:了解Java的反射机制

一、什么是反射?
1.1 定义
反射(Reflection) 是Java语言提供的一种强大机制,允许程序在运行时动态地获取类的完整信息(如成员变量、方法、构造方法等),并且可以动态地创建对象、调用方法、访问属性。

通俗地说:反射就是在程序运行时,让Java程序能够“ introspection”(自省),看清自己的结构,甚至修改自己的行为。

1.2 正常方式 vs 反射方式
对比项 正常方式 反射方式
时机 编译时确定 运行时动态确定
类的信息 写代码时已知 运行时才获取
对象创建 new 类名() Class.forName(“类名”).newInstance()
方法调用 对象.方法名() method.invoke(对象, 参数)
特点 高效、类型安全 灵活、但有一定性能开销
简单示例:

// 正常方式:编译时就知道要使用Student类
Student s = new Student();
s.study();

// 反射方式:运行时才知道要使用哪个类
Class<?> clazz = Class.forName(“com.example.Student”);
Object obj = clazz.newInstance();
Method method = clazz.getMethod(“study”);
method.invoke(obj);

AI写代码
java
运行

二、为什么需要反射?

2.1 核心价值
反射机制使得Java程序从“静态”变为“动态”:

能力 说明
动态加载类 运行时才决定加载哪个类
动态创建对象 类名作为字符串传入,无需硬编码
动态调用方法 方法名作为字符串传入
访问私有成员 可以绕过访问权限检查
2.2 典型应用场景
场景 说明
IDE自动提示 编辑器通过反射获取类的方法和属性
Spring框架 IoC容器通过反射创建和管理Bean
JUnit框架 通过反射识别@Test注解的方法并执行
Tomcat等Web容器 动态加载Servlet类
JSON解析库 通过反射将JSON数据映射到Java对象
注解处理器 运行时读取注解信息
三、反射的核心API
3.1 Class类
Class类是反射的入口,每个Java类在运行时都会对应一个Class对象。

获取Class对象的三种方式:

// 方式1:通过类名.class
Class<?> clazz1 = String.class;

// 方式2:通过对象.getClass()
String str = “hello”;
Class<?> clazz2 = str.getClass();

// 方式3:通过Class.forName()(最常用,动态加载)
Class<?> clazz3 = Class.forName(“java.lang.String”);
AI写代码
java
运行
3.2 反射核心类

类名 作用
Class 代表一个类或接口
Field 代表类的成员变量
Method 代表类的方法
Constructor 代表类的构造方法
Modifier 访问修饰符的工具类
3.3 常用方法一览
Class类常用方法:

方法 说明
getName() 获取类全名(包名+类名)
getSimpleName() 获取类简单名称
getFields() 获取所有public成员变量
getDeclaredFields() 获取所有声明的成员变量(包括private)
getMethods() 获取所有public方法(包括继承的)
getDeclaredMethods() 获取所有声明的方法(不包括继承的)
getConstructors() 获取所有public构造方法
getDeclaredConstructors() 获取所有声明的构造方法
newInstance() 创建实例(调用无参构造)
四、反射的基本使用
4.1 准备工作:定义一个示例类
/**

  • 示例类:用于演示反射机制
    */
    public class Person {
    // 成员变量
    private String name;
    public int age;

    // 构造方法
    public Person() {
    System.out.println(“无参构造方法被调用”);
    }

    private Person(String name) {
    this.name = name;
    System.out.println(“私有构造方法被调用,name=” + name);
    }

    public Person(String name, int age) {
    this.name = name;
    this.age = age;
    System.out.println(“有参构造方法被调用:” + name + “,” + age);
    }

    // 成员方法
    public void sayHello() {
    System.out.println(“Hello, I’m “ + name);
    }

    private void secret() {
    System.out.println(“这是一个私有方法”);
    }

    public String getName() {
    return name;
    }

    public void setName(String name) {
    this.name = name;
    }

    @Override
    public String toString() {
    return “Person{name=’” + name + “‘, age=” + age + “}”;
    }

}
AI写代码
java
运行

4.2 获取类的信息

import java.lang.reflect.*;

public class ReflectionInfoDemo {
public static void main(String[] args) throws ClassNotFoundException {
// 1. 获取Class对象
Class<?> clazz = Class.forName(“Person”);

    // 2. 获取类名
    System.out.println("类全名:" + clazz.getName());
    System.out.println("简单类名:" + clazz.getSimpleName());
    
    // 3. 获取所有public方法(包括继承的)
    System.out.println("\n=== 所有public方法 ===");
    Method[] methods = clazz.getMethods();
    for (Method m : methods) {
        System.out.println("  " + m.getName());
    }
    
    // 4. 获取所有声明的成员变量
    System.out.println("\n=== 所有声明的成员变量 ===");
    Field[] fields = clazz.getDeclaredFields();
    for (Field f : fields) {
        System.out.println("  " + Modifier.toString(f.getModifiers()) + " " + f.getName());
    }
    
    // 5. 获取所有构造方法
    System.out.println("\n=== 所有构造方法 ===");
    Constructor<?>[] constructors = clazz.getDeclaredConstructors();
    for (Constructor<?> c : constructors) {
        System.out.println("  " + c);
    }
}

}
AI写代码
java
运行

4.3 通过反射创建对象

import java.lang.reflect.*;

public class ReflectionCreateDemo {
public static void main(String[] args) throws Exception {
Class<?> clazz = Class.forName(“Person”);

    // 方式1:调用无参构造方法
    System.out.println("=== 方式1:无参构造 ===");
    Person p1 = (Person) clazz.newInstance();  // JDK9后可能过时
    p1.setName("张三");
    p1.sayHello();
    
    // 方式2:调用有参构造方法(推荐)
    System.out.println("\n=== 方式2:有参构造 ===");
    Constructor<?> constructor = clazz.getConstructor(String.class, int.class);
    Person p2 = (Person) constructor.newInstance("李四", 20);
    p2.sayHello();
    
    // 方式3:调用私有构造方法
    System.out.println("\n=== 方式3:私有构造 ===");
    Constructor<?> privateCon = clazz.getDeclaredConstructor(String.class);
    privateCon.setAccessible(true);  // 突破私有访问限制
    Person p3 = (Person) privateCon.newInstance("王五");
    p3.sayHello();
}

}
AI写代码
java
运行

4.4 通过反射调用方法

import java.lang.reflect.*;

public class ReflectionMethodDemo {
public static void main(String[] args) throws Exception {
// 创建对象
Class clazz = Class.forName("Person"); Constructor con = clazz.getConstructor(String.class, int.class);
Person person = (Person) con.newInstance(“小明”, 18);

    // 调用public方法
    System.out.println("=== 调用public方法 ===");
    Method sayHello = clazz.getMethod("sayHello");
    sayHello.invoke(person);
    
    // 调用带参数的方法
    Method setName = clazz.getMethod("setName", String.class);
    setName.invoke(person, "小红");
    sayHello.invoke(person);
    
    // 调用私有方法(需要setAccessible)
    System.out.println("\n=== 调用私有方法 ===");
    Method secret = clazz.getDeclaredMethod("secret");
    secret.setAccessible(true);  // 突破私有权限
    secret.invoke(person);
    
    // 调用有返回值的方法
    Method getName = clazz.getMethod("getName");
    String name = (String) getName.invoke(person);
    System.out.println("getName返回值:" + name);
}

}
AI写代码
java
运行

4.5 通过反射访问成员变量
以下是整理后的代码块格式:

import java.lang.reflect.*;

public class ReflectionFieldDemo {
public static void main(String[] args) throws Exception {
// 创建对象
Class clazz = Class.forName("Person"); Constructor con = clazz.getConstructor(String.class, int.class);
Person person = (Person) con.newInstance(“张三”, 25);

    System.out.println("原始对象:" + person);
    
    // 访问public成员变量
    System.out.println("\n=== 访问public成员变量 ===");
    Field ageField = clazz.getField("age");
    System.out.println("当前age:" + ageField.get(person));
    ageField.set(person, 30);
    System.out.println("修改后age:" + ageField.get(person));
    
    // 访问私有成员变量(需要setAccessible)
    System.out.println("\n=== 访问私有成员变量 ===");
    Field nameField = clazz.getDeclaredField("name");
    nameField.setAccessible(true);
    System.out.println("当前name:" + nameField.get(person));
    nameField.set(person, "李四");
    System.out.println("修改后name:" + nameField.get(person));
    System.out.println("最终对象:" + person);
}

}
AI写代码
java
运行

五、反射的实际应用示例

示例1:通用的toString方法
import java.lang.reflect.*;

class ObjectUtil {
public static String toString(Object obj) {
if (obj == null) return “null”;

    Class<?> clazz = obj.getClass();
    StringBuilder sb = new StringBuilder();
    sb.append(clazz.getSimpleName()).append(" { ");
    
    Field[] fields = clazz.getDeclaredFields();
    for (int i = 0; i < fields.length; i++) {
        fields[i].setAccessible(true);
        try {
            sb.append(fields[i].getName()).append("=");
            sb.append(fields[i].get(obj));
            if (i < fields.length - 1) {
                sb.append(", ");
            }
        } catch (IllegalAccessException e) {
            sb.append("?");
        }
    }
    sb.append(" }");
    return sb.toString();
}

}

class Student {
private String name;
private int score;

Student(String name, int score) {
    this.name = name;
    this.score = score;
}

}

public class GenericToStringDemo {
public static void main(String[] args) {
Student s = new Student(“张三”, 95);
System.out.println(ObjectUtil.toString(s));
}
}
AI写代码
java
运行

示例2:动态调用任意方法
import java.lang.reflect.*;

class DynamicInvoker {
public static Object invoke(Object obj, String methodName, Object… args) {
try {
Class clazz = obj.getClass(); Class[] paramTypes = new Class<?>[args.length];
for (int i = 0; i < args.length; i++) {
paramTypes[i] = args[i].getClass();
}
Method method = clazz.getMethod(methodName, paramTypes);
return method.invoke(obj, args);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}

class Calculator {
public int add(int a, int b) {
return a + b;
}

public String greet(String name) {
    return "Hello, " + name;
}

}

public class DynamicInvokeDemo {
public static void main(String[] args) {
Calculator calc = new Calculator();
Object result1 = DynamicInvoker.invoke(calc, “add”, 10, 20);
System.out.println(“add结果:” + result1);
Object result2 = DynamicInvoker.invoke(calc, “greet”, “张三”);
System.out.println(“greet结果:” + result2);
}
}
AI写代码
java
运行

示例3:模拟JUnit的@Test注解
import java.lang.annotation.;
import java.lang.reflect.
;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@interface Test {}

class MyTestClass {
@Test
public void testMethod1() {
System.out.println(“执行测试方法1”);
}

@Test
public void testMethod2() {
    System.out.println("执行测试方法2");
}

public void normalMethod() {
    System.out.println("普通方法不会被自动执行");
}

}

class TestRunner {
public static void run(Class<?> testClass) throws Exception {
Object instance = testClass.newInstance();
Method[] methods = testClass.getDeclaredMethods();

    for (Method method : methods) {
        if (method.isAnnotationPresent(Test.class)) {
            System.out.print("正在执行:");
            method.invoke(instance);
        }
    }
}

}

public class AnnotationDemo {
public static void main(String[] args) throws Exception {
TestRunner.run(MyTestClass.class);
}
}
AI写代码
java
运行

运行结果
正在执行:执行测试方法1
正在执行:执行测试方法2
AI写代码
六、反射的优缺点
6.1 优点
优点 说明
动态性 运行时动态加载类,提高程序灵活性
通用性 可以编写通用的代码处理各种类型的对象
框架基础 几乎所有Java框架(Spring、Hibernate等)都依赖反射
绕过限制 可以访问私有成员,用于特殊场景(如调试工具)
6.2 缺点
缺点 说明
性能开销 反射调用比直接调用慢,因为需要动态解析
安全问题 可以绕过访问权限,破坏封装性
代码可读性 反射代码不如直接调用直观
编译时检查缺失 错误只能在运行时暴露
七、性能对比示例
以下是整理后的代码块格式:

/**

  • 对比直接调用与反射调用的性能
    */
    public class PerformanceCompare {
    public static void main(String[] args) throws Exception {
    Person person = new Person(“张三”, 20);

    // 1. 直接调用
    long start1 = System.nanoTime();
    for (int i = 0; i < 1000000; i++) {
    person.sayHello();
    }
    long end1 = System.nanoTime();
    System.out.println(“直接调用耗时:” + (end1 - start1) / 1000000 + “ ms”);

    // 2. 反射调用
    Method method = Person.class.getMethod(“sayHello”);
    long start2 = System.nanoTime();
    for (int i = 0; i < 1000000; i++) {
    method.invoke(person);
    }
    long end2 = System.nanoTime();
    System.out.println(“反射调用耗时:” + (end2 - start2) / 1000000 + “ ms”);

    // 3. 反射调用(启用访问检查关闭)
    method.setAccessible(true);
    long start3 = System.nanoTime();
    for (int i = 0; i < 1000000; i++) {
    method.invoke(person);
    }
    long end3 = System.nanoTime();
    System.out.println(“反射(setAccessible)耗时:” + (end3 - start3) / 1000000 + “ ms”);
    }

}
AI写代码
java
运行

代码结构说明:

完整保留了原始注释和逻辑结构
使用标准的Java代码块格式
保持了原有的三个测试部分(直接调用、反射调用、反射调用优化)
时间统计单位统一转换为毫秒(ms)
结论:反射调用通常比直接调用慢2-3倍,setAccessible(true)可以略微提升性能。

八、总结
8.1 核心知识点回顾
知识点 要点
反射的定义 运行时动态获取类信息并操作对象
获取Class对象 .class、getClass()、Class.forName()
核心API Class、Field、Method、Constructor
访问私有成员 setAccessible(true)
主要应用 Spring框架、JUnit、JSON解析等
8.2 使用建议
优先使用直接调用:除非确实需要动态性,否则不要滥用反射

缓存反射对象:如果需要频繁调用,缓存Method、Field等对象

注意安全性:反射可以破坏封装,谨慎使用

考虑性能影响:对性能敏感的代码避免使用反射

8.3 作业完成情况
理解反射机制的定义和作用

掌握获取Class对象的三种方式

能够通过反射创建对象、调用方法、访问属性

了解反射的实际应用场景

了解反射的优缺点

九、课后练习
编写代码,通过反射获取ArrayList类的所有方法名称

使用反射调用String类的toUpperCase()方法

通过反射创建一个HashMap对象,并调用put和get方法

尝试修改一个String对象的内容(利用反射突破不可变性)

扫一扫,分享到微信

微信分享二维码
  • Copyrights © 2026 Shipanxs
  • 访问人数: | 浏览次数:

如果这篇文章对你有帮助,可以请我喝杯茶

支付宝

支付宝扫一扫