匿名内部类使用场景笔记(附练习成果)
一、什么是匿名内部类?
匿名内部类是没有显式类名的内部类,它在定义的同时立即实例化,通常用于一次性使用的场景。语法格式:
new 接口名/父类名() {
// 实现接口中的抽象方法,或重写父类的方法
}
二、典型使用场景
| 场景 | 说明 | 示例 |
|---|---|---|
| 事件监听器 | GUI 编程中为按钮等组件添加临时的回调逻辑 | button.addActionListener(new ActionListener(){...}) |
| 多线程任务 | 创建临时的 Runnable 或 Thread 实例 |
new Thread(new Runnable(){...}).start() |
| 自定义比较器 | 对集合进行一次性排序 | Collections.sort(list, new Comparator<String>(){...}) |
| 策略模式 / 回调 | 传入临时算法或行为 | execute(new Callback(){...}) |
| 临时实现接口 | 如本例:测量代码运行时间,传入待测任务 | TimeKeeping.measure(new Task(){...}) |
三、匿名内部类的特点
- 简洁:免去单独定义一个类的麻烦
- 封闭性:只能使用一次,明确表示“该行为仅在此处有效”
- 可访问外部变量:可以访问外部类的成员变量,以及被
final或事实上不可变的局部变量 - 不能定义静态成员,也不能定义构造方法(因为无名)
- 会持有外部类引用,使用不当可能造成内存泄漏
四、练习成果:用匿名内部类测量方法运行时间
4.1 设计思路
- 定义一个
Task接口,内含需要执行的任务方法taskFunction() - 编写
TimeKeeping工具类,提供一个静态方法measure(Task task),内部记录开始/结束时间并计算耗时 - 在
main方法中通过匿名内部类实现Task接口,将想要测量的代码放入taskFunction()中,并传递给measure方法
4.2 代码实现
Task.java – 任务接口
package blogAissgn;
public interface Task {
void taskFunction();
}
TimeKeeping.java – 计时工具类
package blogAissgn;
public class TimeKeeping {
public static void measure(Task task) {
long startTime = System.nanoTime();
task.taskFunction();
long endTime = System.nanoTime();
double seconds = (endTime - startTime) / 1_000_000_000.0; // 转换为秒
System.out.println("这个任务的方法消耗的时间:" + seconds + " second");
}
}
TaskMain.java – 使用匿名内部类进行测量
package blogAissgn;
public class TaskMain {
public static void main(String[] args) {
// 使用匿名内部类实现 Task 接口,并重写 taskFunction 方法
TimeKeeping.measure(new Task() {
@Override
public void taskFunction() {
// 这里放入你想要测量运行时间的代码
for (int i = 1; i < 200000000; i++) {
Math.sqrt(i);
}
}
});
}
}
4.3 运行结果示例
这个任务的方法消耗的时间:0.027689301 second
4.4 练习心得
- 匿名内部类非常适合临时定义一段行为并将其作为参数传递。本例中,我不需要专门写一个
MyTask类,直接在调用处定义任务逻辑,代码更紧凑。 TimeKeeping类成为一个通用的计时工具,可与任何实现了Task接口的类(包括匿名内部类)配合使用,体现了策略模式的思想。- 当需要测量的代码很短且只在当前场景使用时,匿名内部类比单独定义一个类更方便;但如果需要重复使用同一个任务,应该定义命名类。
五、小结
匿名内部类是 Java 中一种“即时使用、用完即弃”的类定义方式,特别适合作为回调、监听器、策略或任何一次性实现接口/抽象类的场景。通过上面的计时器练习,可以清晰看到它如何简化代码结构,同时保持功能完整。
