1. 什么是匿名内部类?

匿名内部类(Anonymous Inner Class)是 Java 中一种特殊的局部内部类,它没有类名,使用 new 关键字直接实例化一个接口或抽象类,并同时实现其方法。语法形式:

1
2
3
接口名 对象名 = new 接口名() {
// 实现接口方法
};

匿名内部类本质上是语法糖,编译后会生成一个单独的 .class 文件(如 Outer$1.class)。

2. 主要使用场景

2.1 事件处理(GUI 编程)

在 Swing 或 Android 开发中,按钮点击、键盘事件等通过监听器处理。匿名内部类可以直接在组件上注册事件,代码紧凑。

1
2
3
4
5
6
button.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
System.out.println("按钮被点击");
}
});

2.2 线程创建

快速启动一个新线程,重写 Runnable 的 run 方法:

1
2
3
4
5
6
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("新线程运行");
}
}).start();

2.3 集合排序(Comparator)

对集合元素自定义排序,无需单独编写比较器类:

1
2
3
4
5
6
7
List<String> list = Arrays.asList("apple", "banana", "cherry");
Collections.sort(list, new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return o1.length() - o2.length();
}
});

2.4 临时实现接口或抽象类

当某个接口或抽象类只需要一次实现时,匿名内部类避免创建独立的 .java 文件。

1
2
3
4
5
6
7
8
9
10
11
abstract class Animal {
abstract void sound();
}

Animal dog = new Animal() {
@Override
void sound() {
System.out.println("汪汪");
}
};
dog.sound();

2.5 回调机制

将业务逻辑以匿名内部类的形式传入方法,实现回调(例如文件过滤):

1
2
3
4
5
6
File[] files = new File(".").listFiles(new FileFilter() {
@Override
public boolean accept(File pathname) {
return pathname.getName().endsWith(".java");
}
});

2.6 简化设计模式

如模板方法模式、策略模式等,可用匿名内部类提供具体实现,减少类爆炸。

3. 匿名内部类 vs Lambda 表达式

从 Java 8 开始,函数式接口(只有一个抽象方法的接口)可以用 Lambda 简化,上面的许多场景可改写为:

1
2
3
4
// Lambda 形式
button.addActionListener(e -> System.out.println("按钮被点击"));
new Thread(() -> System.out.println("新线程运行")).start();
Collections.sort(list, (a, b) -> a.length() - b.length());

对比:

特性 匿名内部类 Lambda
代码量 较多 简洁
访问局部变量 要求变量是 final 或 effectively final 相同要求
this 含义 指向匿名内部类自身 指向外部类实例
适用范围 接口、抽象类、具体类 仅函数式接口
结论: 对于函数式接口,优先使用 Lambda;若需要重写多个方法、或需要类自身的字段/方法,仍使用匿名内部类。

4. 注意事项

内存泄漏:匿名内部类持有外部类的引用,可能导致外部类无法被 GC 回收,在长生命周期场景(如静态变量、线程)中需注意。

可读性:过于复杂的匿名内部类会降低代码可读性,此时应考虑创建独立的具名类。

编译产物:大量匿名内部类会产生很多 $1.class 等文件,影响构建速度。

5. 总结

匿名内部类适用于一次性、轻量级的实现需求,尤其在 Lambda 出现前是 Java 实现回调的核心手段。如今,在非函数式接口或多方法实现的场景中,它依然不可或缺。理解匿名内部类的原理,有助于读懂旧代码并写出更优雅的 Java 程序。