匿名内部类
1. 定义:无类名(底层自动分配类名“外部类名$1”),既是类也是对象,定义在外部类的局部位置,例如方法体和代码块中,通过new类或接口并在大括号里重写方法来实现。
2. 使用场景:需要实现接口,重写接口或类的方法,但只需要用到一次的类,可以用匿名内部类来简化开发,省去开发人员手动创建类和实现接口的过程,将这些过程交给编译器底层实现。直接new接口或类,在大括号里面实现所需的方法就可以了。编译类型是接口,运行类型是匿名内部类。
3. 匿名内部类并不是真的没有类名,只是开发人员交给底层去分配,实际上系统底层会给匿名内部类分配类名,规则是“外部类名$X”,X是匿名内部类的编号,从1开始。
4. 使用匿名内部类必须new分配空间,所以它既是类也是对象,这个类分配完空间后就不能再使用了。
public class AnonymousInnerClass {
public static void main(String[] args) {
Outer04 outer04 = new Outer04();
outer04.method();
}
}
class Outer04 { // 外部类
private int n1 = 10; // 属性
// 基于接口的匿名内部类的使用
public void method() { // 方法
IA ia = new IA() {
@Override
public void cry() {
// 重写接口中的方法
System.out.println("重写的方法...");
}
};
ia.cry();
System.out.println("匿名内部类的运行类型是: " + ia.getClass());
System.out.println("============================");
// 基于类的匿名内部类的使用
Father father = new Father("jack") {
@Override
public void test() {
System.out.println("重写的方法...");
}
};
father.test();
System.out.println("匿名内部类的运行类型是: " + father.getClass());
}
}
interface IA { // 接口
public void cry();
}
abstract class Father {
public Father(String name) { // 构造器
}
public abstract void test(); // 抽象方法
}
运行结果:
5. 因为匿名内部类返回的是一个对象,所以可以直接在后面通过"匿名内部类.方法名(参数列表)"的形式来直接调用方法。
public class AnonymousDetail {
public static void main(String[] args) {
Outer outer = new Outer();
outer.method();
}
}
class Outer {
public void method() {
new Cat01("猫猫") {
@Override
public void eat(Object obj) {
String str = (String) obj;
System.out.println("猫吃: " + str);
}
}.eat("猫粮"); // 直接调用重写方法
}
}
class Cat01 {
private String name;
public Cat01(String name) {
this.name = name;
}
public void eat(Object obj) {
}
}
6. 和局部内部类一样,匿名内部类也可以直接访问外部类的所有成员,但外部类不能直接访问内部类的成员。
7. 和局部内部类一样,匿名内部类访问外部类成员依然要用“外部类.this.外部类属性名”的方式访问。
匿名内部类的最佳实践
public class AnonymousExercise02 {
public static void main(String[] args) {
CellPhone cellPhone = new CellPhone();
cellPhone.alarmClock(new Bell() {
@Override
public void ring() {
System.out.println("起床啦...");
}
});
cellPhone.alarmClock(new Bell() {
@Override
public void ring() {
System.out.println("闹铃响了...");
}
});
}
}
interface Bell{
void ring();
}
class CellPhone {
public void alarmClock(Bell bell) {
bell.ring();
}
}
运行结果: