Lambda 简写的依据java
可以使用 Lambda 的依据是必须有相应的函数接口(函数接口,是指内部只有一个抽象方法的接口),也就是说你并不能在代码的任何地方任性的写Lambda表达式。Lambda表达式另外一个依据是类型推断机制(在上下文信息足够的状况下,编译器能够推断出参数表的类型,而不须要显式指名)程序员
Anonymous Classeside
匿名内部类仍然是一个类,只是不须要程序员显示指定类名,编译器会自动为该类取名。所以若是有以下形式的代码,编译以后将会产生两个class文件:函数
public class MainAnonymousClass {
public static void main(String[] args) {
new Thread(new Runnable(){
@Override
public void run(){
System.out.println("Anonymous Class Thread run()");
}
}).start();;
}
}
复制代码
编译以后文件分布以下,两个class文件分别是主类和匿名内部类产生的:spa
进一步分析主类MainAnonymousClass.class的字节码,可发现其建立了匿名内部类的对象:code
// javap -c MainAnonymousClass.class
public class MainAnonymousClass {
...
public static void main(java.lang.String[]);
Code:
0: new #2 // class java/lang/Thread
3: dup
4: new #3 // class MainAnonymousClass$1 /*建立内部类对象*/
7: dup
8: invokespecial #4 // Method MainAnonymousClass$1."<init>":()V
11: invokespecial #5 // Method java/lang/Thread."<init>":(Ljava/lang/Runnable;)V
14: invokevirtual #6 // Method java/lang/Thread.start:()V
17: return
}
复制代码
Lambda 表达式的实现cdn
Lambda 表达式经过 invokedynamic 指令实现,书写 Lambda 表达式不会产生新的类。对象
public class MainLambda {
public static void main(String[] args) {
new Thread(
() -> System.out.println("Lambda Thread run()")
).start();;
}
}
复制代码
编译以后:blog
经过javap反编译命名,咱们更能看出Lambda表达式内部表示的不一样:接口
// javap -c -p MainLambda.class
public class MainLambda {
...
public static void main(java.lang.String[]);
Code:
0: new #2 // class java/lang/Thread
3: dup
4: invokedynamic #3, 0 // InvokeDynamic #0:run:()Ljava/lang/Runnable; /*使用invokedynamic指令调用*/
9: invokespecial #4 // Method java/lang/Thread."<init>":(Ljava/lang/Runnable;)V
12: invokevirtual #5 // Method java/lang/Thread.start:()V
15: return
private static void lambda$main$0(); /*Lambda表达式被封装成主类的私有方法*/
Code:
0: getstatic #6 // Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #7 // String Lambda Thread run()
5: invokevirtual #8 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: return
}
复制代码
反编译以后咱们发现Lambda表达式被封装成了主类的一个私有方法,并经过invokedynamic指令进行调用。