匿名内部类最实用的场景是快速创建接口或抽象类的一次性实例,常用于事件监听、函数式接口(如runnable、comparator)及需调用父类方法或定义字段的场合。

匿名内部类最实用的场景,就是快速创建接口或抽象类的一次性实例——不用单独定义实现类,代码写在哪,实例就建在哪,干净利落。
用在事件监听这种“一次一用”的地方
比如给按钮加点击响应,Swing 或 Android(老式写法)里特别常见。接口只有一个方法,没必要专门写个 MyClickListener 类。
- 直接 new 接口名 + 大括号,重写方法即可
- 方法体里写业务逻辑,访问外部变量时注意:局部变量得是 final 或 effectively final(Java 8+ 允许不加 final 关键字,但不能改值)
- 示例:
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(context, "点到了!", Toast.LENGTH_SHORT).show();
}
});
配合函数式接口(尤其是 Runnable、Comparator、Callable)
这些接口天然适合匿名内部类——方法少、逻辑短、调用完就丢。
-
new Thread(new Runnable() { ... }).start();是经典用法(现在更推荐 Lambda,但理解匿名类是基础) -
Collections.sort(list, new Comparator<string>() { ... });</string>可以按需定制排序逻辑,不污染其他地方 - 关键点:匿名类对象可以持有对外部作用域的引用(比如方法参数、局部变量),所以能自然“捕获”上下文
绕过无参构造限制,灵活初始化
如果某个抽象类没有无参构造器,或者你想在创建时传参并做点初始化,匿名类可以立即补全构造逻辑。
- 例如:
new AbstractList<string>() {<br> @Override public String get(int i) { return "item" + i; }<br> @Override public int size() { return 10; }<br> };</string> - 它本质上是继承了
AbstractList的子类,并实现了抽象方法——编译器自动生成类名(如OuterClass$1.class) - 注意:不能同时 extends 和 implements,匿名类只能继承一个类 或 实现一个接口(不能两者兼得)
和 Lambda 的区别与取舍
匿名内部类不是过时技术,而是 Lambda 的底层基础。当需要以下情况时,它仍不可替代:
- 实现多个抽象方法的接口(Lambda 只支持函数式接口)
- 需要调用父类方法(比如
super.xxx())或使用this指向当前匿名类实例 - 需要定义额外字段或构造逻辑(Lambda 是纯方法,无法持状态)
- 调试时想看清具体类名(Lambda 编译后类名无意义,匿名类至少带 $1、$2)











