在学习java的过程中,我们都知道接口是不能创建对象的,但今天我看到这样一行代码
Animal bird= () -> {
System.out.println("鸟吃虫");
};
这里看起来就像是Animal接口创建了一个bird对象,经查询,这个叫Lambda表达式,这里当然不是接口创建了一个对象。要知道原因,得从匿名内部类说起。
先看代码
Animal接口
public interface Animal {
public void eat();
}
Animal的实现类Dog类
public class Dog implements Animal{
@Override
public void eat() {
System.out.println("狗狗吃骨头");
}
public void run(){
System.out.println("狗狗跑");
}
}
我们对接口的使用,就是创建Dog这样的实现类来重写接口里的方法,利用多态创建对象
Animal cat=new Dog();
但有这样一种情况,我不在乎Animal的实现类叫什么,也不需要这个实现类能被用到其他类,能不能不写实现类的名字?
于是就有了匿名内部类这样的写法
Animal cat=new Animal() {
@Override
public void eat() {
System.out.println("猫猫吃鱼");
}
public void run(){
System.out.println("猫猫跑");
}
};
这个写法对于初学者看起来很怪,不看大括号里的内容,就像是创建了接口的对象,但是看大括号里的内容,不难知道是匿名了的实现类重写了接口的eat()方法,而run()是我自己加的,先不看。Animal()后的全部就和一般实现类的写法是等同的,只是匿名了。
既然是匿名类,也就是说没办法知道它的类名,而我们如果要调用它的run()方法,就得知道类名,像这样
new Dog().run;
这让我想到toString()
我们建立Test类
public class Test {
public static void main(String[] args) {
Animal cat=new Animal() {
@Override
public void eat() {
System.out.println("猫猫吃鱼");
}
public void run(){
System.out.println("猫猫跑");
}
};
System.out.println(cat.toString());
System.out.println(new Test().toString());
Dog d=new Dog();
System.out.println(d.toString());
}
}
运行结果
Test$1@404b9385
Test@6d311334
Dog@3d075dc0
看上去那个匿名类的类名叫Test$1,但打出Test$1他会告诉你根本就没这个类,我们再写一个匿名类
public class Test {
public static void main(String[] args) {
Animal cat=new Animal() {
@Override
public void eat() {
System.out.println("猫猫吃鱼");
}
public void run(){
System.out.println("猫猫跑");
}
};
Animal bird=new Animal() {
@Override
public void eat() {
System.out.println("鸟吃虫");
}
};
System.out.println(cat.toString());
System.out.println(new Test().toString());
System.out.println(bird.toString());
}
}
运行结果
Test$1@404b9385
Test@6d311334
Test$2@214c265e
发现匿名类在toString()里似乎就是那么命名的,但讲道理,匿名类确实做到了匿名,没法使用他的类名。不需要管类名,只管实现接口。
搞清楚什么是匿名内部类,再回到我们最开始的那个Lambda表达式。看上去就是匿名内部类的简洁表达,但多少还是有点不同
Animal bird= () -> {
System.out.println("鸟吃虫");
};
Animal bird=new Animal() {
@Override
public void eat() {
System.out.println("鸟吃虫");
}
};
Lambda表达式只适用于只需要重写一个方法的情况,多了不行。除此以外,确实是一种更好的简化表达,作用和匿名内部类还是一样的。