匿名内部类的使用场景

要求:

使用匿名内部类来封装一个需要计时的任务,在调用任务前后记录时间,从而计算执行耗时。

代码

public class TimeUtil {
    
    // 定义一个任务接口
    interface Task {
        void execute();
    }
    
    // 计时方法,接收一个 Task 实例(可使用匿名内部类传入)
    public static double measureSeconds(Task task) {
        long start = System.nanoTime();
        task.execute();
        long end = System.nanoTime();
        return (end - start) / 1_000_000_000.0; // 转换为秒
    }
    
    public static void main(String[] args) {
        // 使用匿名内部类传入需要计时的代码块
        double seconds = measureSeconds(new Task() {
            @Override
            public void execute() {
                // 这里放你想测量执行时间的方法
                try {
                    Thread.sleep(500);  // 模拟耗时操作,500毫秒
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                // 或者调用其他业务方法
                // someMethod();
            }
        });
        
        System.out.printf("方法执行了 %.3f 秒\n", seconds);
    }
}

使用匿名内部类优点:

避免为一次性任务单独创建一个类文件,代码更紧凑。

可以直接访问所在方法的局部变量

Java的反射机制

何为反射

反射(Reflection) 是 Java 语言中一种强大的机制,它允许运行中的程序获取自身或任意类的内部信息(如成员变量、方法、构造器),并能动态地创建对象、调用方法、修改属性,甚至打破封装性(访问 private 成员)。简单说:反射让 Java 从“静态语言”在运行时具备了某种“动态语言”的特性。

为什么需要反射

很多框架(Spring、MyBatis、Hibernate)在编译时并不知道你会定义哪些类,但它们需要扫描、实例化、调用你的类 —— 这时就必须依靠反射。

反射的核心类

类名 作用 
Class 代表一个类或接口,反射的入口
Constructor 代表构造方法
Method 代表普通方法
Field 代表成员变量
Parameter 代表方法参数(Java 8+)
Modifier 解析访问修饰符(public, private 等)

获取Class对象的三种方式

// 方式1:通过类的静态属性 .class
Class<User> clazz1 = User.class;

// 方式2:通过对象的 getClass() 方法
User user = new User();
Class<? extends User> clazz2 = user.getClass();

// 方式3:通过 Class.forName() 全限定类名(最常用,动态加载)
Class<?> clazz3 = Class.forName("com.example.User");

常用反射操作

通过反射创建对象

// 1. 调用无参构造
User obj = (User) clazz.getDeclaredConstructor().newInstance();

// 2. 调用有参构造
Constructor<?> constructor = clazz.getConstructor(String.class, int.class);
User obj2 = (User) constructor.newInstance("张三", 25);

获取并调用方法

// 获取 public 方法
Method method = clazz.getMethod("setName", String.class);
method.invoke(obj, "李四");

// 获取 private 方法(需暴力反射)
Method privateMethod = clazz.getDeclaredMethod("secretMethod");
privateMethod.setAccessible(true);   // 打破封装
privateMethod.invoke(obj);

获取并修改字段

Field field = clazz.getDeclaredField("age");
field.setAccessible(true);
field.set(obj, 30);
System.out.println(field.get(obj));  // 输出 30

完整示例

public class ReflectDemo {
    public static void main(String[] args) throws Exception {
        // 1. 获取 Class
        Class<?> clazz = Class.forName("com.example.User");

        // 2. 创建对象(无参构造)
        Object user = clazz.getDeclaredConstructor().newInstance();

        // 3. 调用 setName 方法
        Method setName = clazz.getMethod("setName", String.class);
        setName.invoke(user, "王小明");

        // 4. 调用 getName 方法并打印
        Method getName = clazz.getMethod("getName");
        String name = (String) getName.invoke(user);
        System.out.println("用户名:" + name);

        // 5. 直接修改私有字段 age
        Field ageField = clazz.getDeclaredField("age");
        ageField.setAccessible(true);
        ageField.set(user, 22);
        System.out.println("年龄:" + ageField.get(user));
    }
}

反射优缺点

优点

动态性:运行期决定加载哪个类、调用哪个方法,利于实现框架。

通用性:编写不依赖具体类型的代码(如 JSON 解析库、ORM 工具)。

调试/测试工具:可绕过 private 限制进行单元测试或依赖注入。

缺点

性能开销:反射调用比正常调用慢(因为涉及动态解析、安全检查)。JVM 很难优化反射代码。

安全问题:setAccessible(true) 破坏了封装性,可能引发安全风险。

代码可读性下降:反射代码更为晦涩,且 IDE 不提供方法/字段名的自动重构。

更多推荐