内部类分4种:成员内部类,静态内部类,局部内部类和匿名内部类。我们今天讨论的就是其中最常见的匿名内部类。从名称可以看出,就是没有名字的类,因为没有名字,所以总归和其它普通类有一些些区别:
先定义一个输出对象的接口:
public interface IOut {
void println(String msg);
}
再定义一个抽象类:
public abstract class BaseOut implements IOut {
private final int bufferSize;
public BaseOut() {
bufferSize = 1024;
}
public BaseOut(int bufferSize) {
this.bufferSize = bufferSize;
}
@Override
public abstract void println(String msg);
}
开始演示:
public class Run {
public static void main(String[] args) {
// 1.定义的时候直接实例化
// 2.实现了接口
final IOut out0 = new IOut() {
// static String name; // 4.不能有静态成员
// static void print() {} // 4.不能有静态方法
// static {} // 4.不能有静态初始化块
// abstract void print(); // 3.不能有抽象方法
@Override
public void println(String msg) {
System.out.println(msg);
}
};
// 2.继承了父类,无参构造函数
BaseOut out1 = new BaseOut() {
@Override
public void println(String msg) {
out0.println(msg); // 5.使用了外部类局部变量,final修饰
}
};
// 2.继承了父类,有参构造函数
BaseOut out2 = new BaseOut(2048) {
@Override
public void println(String msg) {
out1.println(msg); // 5.使用了外部类局部变量,java8可以不用final修饰
}
};
}
}
在演示lambda之前,先修改下IOut接口,添加默认方法和静态方法:
@FunctionalInterface
public interface IOut {
void println(String msg);
/**
* 默认方法,由实现类调用
*/
default void print(String msg) {
System.out.print(msg);
}
/**
* 静态方法
*/
static void printf(String fmt, Object... args) {
System.out.printf(fmt, args);
}
}
最重要的,加了一个注解:@FunctionalInterface,表明这个接口是函数式接口:有且只有一个抽象方法的接口。这个注解是给编译器严格检查使用的,同时也代表:可以添加这个注解的接口,在创建对应的匿名内部类时,可以使用lambda:
public class Run {
public static void main(String[] args) {
// 函数式接口,内部类实现只有一个函数,这个时候使用lambda
IOut out0 = (msg) -> {
System.out.println(msg);
};
// 参数列表只有一个参数,去掉括号
IOut out1 = msg -> {
System.out.println(msg);
};
// 方法体只有一条语句,去掉花括号和分号
IOut out2 = msg -> System.out.println(msg);
// 很巧的,方法体实现只是引用了其它对象的方法,使用方法引用
IOut out3 = System.out::println;
}
}
从上面的简单示例可以看出:如果一个接口是函数式接口,并且创建这个函数式接口的匿名内部类时,也只是实现了抽象方法,不添加任何其它方法,保证实现的方法唯一时,就可以使用lambda(匿名函数)。因为确定实现的就是那个函数,所以函数名可以省去,只要申明形参名(为了给方法体使用),形参类型都可以省去,然后使用符号->连接方法体。
上面说的第3点,具体看demo:
public class Run {
public static void main(String[] args) {
// 匿名内部类
IOut out0 = new IOut() {
@Override
public void println(String msg) {
println(msg); // 实例方法
IOut.printf(msg); // 静态方法
}
};
// lambda
IOut out1 = msg -> {
// 无法调用继承得到的默认方法
IOut.printf(msg);
};
}
}