匿名类是指没有类名的内部类,必须在创建时使用 new 语句来声明类
。其语法形式如下:
new <类或接口>() {
// 类的主体
};
这种形式的 new 语句声明一个新的匿名类,它对一个给定的类进行扩展,或者实现一个给定的接口。使用匿名类可使代码更加简洁、紧凑,模块化程度更高。
匿名类有两种实现方式:
- 继承一个类,重写其方法。
- 实现一个接口(可以是多个),实现其方法。
下面通过代码来说明。
public class Out {
void show() {
System.out.println("调用 Out 类的 show() 方法");
}
}
public class TestAnonymousInterClass {
// 在这个方法中构造一个匿名内部类
private void show() {
Out anonyInter = new Out() {
// 获取匿名内部类的实例
void show() {
System.out.println("调用匿名类中的 show() 方法");
}
};
anonyInter.show();
}
public static void main(String[] args) {
TestAnonymousInterClass test = new TestAnonymousInterClass();
test.show();
}
}
程序的输出结果如下:
调用匿名类中的 show() 方法
从输出结果可以看出,匿名内部类有自己的实现。
提示:匿名内部类实现一个接口的方式与实现一个类的方式相同,这里不再赘述。
例2:
最常用的情况就是在多线程的实现上,因为要实现多线程必须继承Thread类或是继承Runnable接口
在这里我们看到使用匿名内部类我们必须要继承一个父类或者实现一个接口,当然也仅能只继承一个父类或者实现一个接口。同时它也是没有class关键字,这是因为匿名内部类是直接使用new来生成一个对象的引用。当然这个引用是隐式的。
abstract class Bird{
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public abstract int fly();
}
public class Test {
public void test(Bird bird){
System.out.println(bird.getName()+"能够飞"+bird.fly()+"米");
}
public static void main(String[] args) {
Test test=new Test();
test.test(new Bird(){
@Override
public int fly() {
return 10;
}
public String getName(){
return "无翼鸟";
}
});
}
}
无翼鸟能够飞10米
在Test类中,test()方法接受一个Bird类型的参数,同时我们知道一个抽象类是没有办法直接new的,我们必须要先有实现类才能new出来它的实现类实例。所以在mian方法中直接使用匿名内部类来创建一个Bird实例。
由于匿名内部类不能是抽象类,所以它必须要实现它的抽象父类或者接口里面所有的抽象方法。
匿名类有如下特点:
1)匿名类和局部内部类一样,可以访问外部类的所有成员。如果匿名类位于一个方法中,则匿名类只能访问方法中 final 类型的局部变量和参数。
public static void main(String[] args) {
int a = 10;
final int b = 10;
Out anonyInter = new Out() {
void show() {
// System.out.println("调用了匿名类的 show() 方法"+a); // 编译出错
System.out.println("调用了匿名类的 show() 方法"+b); // 编译通过
}
};
anonyInter.show();
}
从 Java 8 开始添加了 Effectively final 功能,在 Java 8 及以后的版本中代码第 6 行不会出现编译错误,
2)匿名类中允许使用非静态代码块进行成员初始化操作。
Out anonyInter = new Out() {
int i; { // 非静态代码块
i = 10; //成员初始化
}
public void show() {
System.out.println("调用了匿名类的 show() 方法"+i);
}
};
3)匿名类的非静态代码块会在父类的构造方法之后被执行。
注意事项
在使用匿名内部类的过程中,我们需要注意如下几点:
1、使用匿名内部类时,我们必须是继承一个类或者实现一个接口,但是两者不可兼得,同时也只能继承一个类或者实现一个接口。
2、匿名内部类中是不能定义构造函数的。
3、匿名内部类中不能存在任何的静态成员变量和静态方法。
4、匿名内部类为局部内部类,所以局部内部类的所有限制同样对匿名内部类生效。
5、匿名内部类不能是抽象的,它必须要实现继承的类或者实现的接口的所有抽象方法。