代码拉取完成,页面将自动刷新
引用 -> Java Lambda表达式 实现原理分析 引用 -> java8 探讨与分析匿名内部类、lambda表达式、方法引用的底层实现
@FunctionalInterface
public interface Flyable {
void fly();
}
public class LambdaTest {
public static void main(String[] args) {
Flyable flyable = () -> System.out.println("飞起来了");
flyable.fly();
}
}
javac -encoding utf-8 LambdaTest.java
java LambdaTest
javap -p Flyable.class
javap -p LambdaTest.class
由此可见 : 自动生成了 private static void lambda$main$0();
javap -p -v LambdaTest.class
Classfile LambdaTest.class
Last modified 2021-1-23; size 998 bytes
MD5 checksum 49cbf38c127aef6ab71674fd641638a2
Compiled from "LambdaTest.java"
public class LambdaTest
minor version: 0
major version: 52
flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
#1 = Methodref #8.#18 // java/lang/Object."<init>":()V
#2 = InvokeDynamic #0:#23 // #0:fly:()LFlyable;
#3 = InterfaceMethodref #24.#25 // Flyable.fly:()V
#4 = Fieldref #26.#27 // java/lang/System.out:Ljava/io/PrintStream;
#5 = String #28 // 飞起来了
#6 = Methodref #29.#30 // java/io/PrintStream.println:(Ljava/lang/String;)V
#7 = Class #31 // LambdaTest
#8 = Class #32 // java/lang/Object
#9 = Utf8 <init>
#10 = Utf8 ()V
#11 = Utf8 Code
#12 = Utf8 LineNumberTable
#13 = Utf8 main
#14 = Utf8 ([Ljava/lang/String;)V
#15 = Utf8 lambda$main$0
#16 = Utf8 SourceFile
#17 = Utf8 LambdaTest.java
#18 = NameAndType #9:#10 // "<init>":()V
#19 = Utf8 BootstrapMethods
#20 = MethodHandle #6:#33 // invokestatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/
invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
#21 = MethodType #10 // ()V
#22 = MethodHandle #6:#34 // invokestatic LambdaTest.lambda$main$0:()V
#23 = NameAndType #35:#36 // fly:()LFlyable;
#24 = Class #37 // Flyable
#25 = NameAndType #35:#10 // fly:()V
#26 = Class #38 // java/lang/System
#27 = NameAndType #39:#40 // out:Ljava/io/PrintStream;
#28 = Utf8 飞起来了
#29 = Class #41 // java/io/PrintStream
#30 = NameAndType #42:#43 // println:(Ljava/lang/String;)V
#31 = Utf8 LambdaTest
#32 = Utf8 java/lang/Object
#33 = Methodref #44.#45 // java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/Method
Handle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
#34 = Methodref #7.#46 // LambdaTest.lambda$main$0:()V
#35 = Utf8 fly
#36 = Utf8 ()LFlyable;
#37 = Utf8 Flyable
#38 = Utf8 java/lang/System
#39 = Utf8 out
#40 = Utf8 Ljava/io/PrintStream;
#41 = Utf8 java/io/PrintStream
#42 = Utf8 println
#43 = Utf8 (Ljava/lang/String;)V
#44 = Class #47 // java/lang/invoke/LambdaMetafactory
#45 = NameAndType #48:#52 // metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType
;)Ljava/lang/invoke/CallSite;
#46 = NameAndType #15:#10 // lambda$main$0:()V
#47 = Utf8 java/lang/invoke/LambdaMetafactory
#48 = Utf8 metafactory
#49 = Class #54 // java/lang/invoke/MethodHandles$Lookup
#50 = Utf8 Lookup
#51 = Utf8 InnerClasses
#52 = Utf8 (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
#53 = Class #55 // java/lang/invoke/MethodHandles
#54 = Utf8 java/lang/invoke/MethodHandles$Lookup
#55 = Utf8 java/lang/invoke/MethodHandles
{
public LambdaTest();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
LineNumberTable:
line 6: 0
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=1, locals=2, args_size=1
0: invokedynamic #2, 0 // InvokeDynamic #0:fly:()LFlyable;
5: astore_1
6: aload_1
7: invokeinterface #3, 1 // InterfaceMethod Flyable.fly:()V
12: return
LineNumberTable:
line 9: 0
line 10: 6
line 11: 12
private static void lambda$main$0();
descriptor: ()V
flags: ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC
Code:
stack=2, locals=0, args_size=0
0: getstatic #4 // Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #5 // String 飞起来了
5: invokevirtual #6 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: return
LineNumberTable:
line 9: 0
}
SourceFile: "LambdaTest.java"
InnerClasses:
public static final #50= #49 of #53; //Lookup=class java/lang/invoke/MethodHandles$Lookup of class java/lang/invoke/MethodHandles
BootstrapMethods:
0: #20 invokestatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invok
e/MethodType;)Ljava/lang/invoke/CallSite;
Method arguments:
#21 ()V
#22 invokestatic LambdaTest.lambda$main$0:()V
#21 ()V
java -Djdk.internal.lambda.dumpProxyClasses LambdaTest
import java.lang.invoke.LambdaForm.Hidden;
// $FF: synthetic class
final class LambdaTest$$Lambda$1 implements Flyable {
private LambdaTest$$Lambda$1() {
}
@Hidden
public void fly() {
LambdaTest.lambda$main$0();
}
}
public class LambdaTest {
public static void main(String[] args) {
Flyable flyable = new Flyable() {
@Override
public void fly() {
System.out.println("飞起来了");
}
};
flyable.fly();
}
}
可以看到,在编译期就生成了匿名内部类的class文件
javap -p LambdaTest$1.class
Compiled from "LambdaTest.java"
final class LambdaTest$1 implements Flyable {
LambdaTest$1();
public void fly();
}
方式 | javac编译 | javap反编译 | jvm调参并第二次编译 (运行) |
---|---|---|---|
匿名内部类 | 额外生成class | 未见invoke dynamic
|
|
指令 | 无变化 | ||
lambda表达式 | 未生成class,但额外生成了一个static的方法 | 发现invoke dynamic
|
发现额外的class |
下面的译本,原文Java-8-Lambdas-A-Peek-Under-the-Hood 匿名内部类具有可能影响应用程序性能的不受欢迎的特性。
基于以上4点,lambda表达式的实现不能直接在编译阶段就用匿名内部类实现
,而是需要一个稳定的二进制表示,它提供足够的信息,同时允许JVM在未来采用其他可能的实现策略。
解决上述解释的问题,Java语言和JVM工程师决定将翻译策略的选择推迟到运行时。Java 7 中引入的新的 invokedynamic
字节码指令为他们提供了一种高效实现这一目标的机制。将lambda表达式转换为字节码需要两个步骤:
invokedynamic
调用站点 ( 称为lambda工厂 ),当调用该站点时,返回一个函数接口实例,lambda将被转换到该接口;import java.util.Random;
public class LambdaTest {
public static void printString(String s, Integer i, Print<String, Integer> print) {
print.print(s, i);
}
public static void printCount(Count<String> count) {
String sss = count.count();
System.out.println("sss = " + sss);
}
public static void main(String[] args) {
printString("testPrint1", 1, (s, ii) -> System.out.println(s + ii));
printString("testPrint2", 2, (s, ii) -> System.out.println(s + ii));
printString("testPrint3", 3, (s, ii) -> System.out.println(s + ii));
printString("testPrint4", 4, (s, ii) -> System.out.println(s + ii));
printString("testPrint5", 5, (s, ii) -> System.out.println(s + ii));
printString("testPrint6", 6, (s, ii) -> System.out.println(s + ii));
printString("testPrint7", 7, (s, ii) -> System.out.println(s + ii));
printString("testPrint8", 8, (s, ii) -> System.out.println(s + ii));
printString("testPrint9", 9, (s, ii) -> System.out.println(s + ii));
printString("testPrint10", 10, (s, ii) -> System.out.println(s + ii));
printString("testPrint11", 11, (s, ii) -> System.out.println(s + ii));
printString("testPrint12", 12, (s, ii) -> System.out.println(s + ii));
printString("testPrint13", 13, (s, ii) -> System.out.println(s + ii));
printString("testPrint14", 14, (s, ii) -> System.out.println(s + ii));
printString("testPrint15", 15, (s, ii) -> System.out.println(s + ii));
printString("testPrint16", 16, (s, ii) -> System.out.println(s + ii));
printCount(() -> "testCount" + 1);
Random random = new Random();
printCount(() -> String.valueOf(random.nextInt(1000000)));
printCount(() -> String.valueOf(random.nextInt(1000000)));
printCount(() -> String.valueOf(random.nextInt(1000000)));
printCount(() -> String.valueOf(random.nextInt(1000000)));
printCount(() -> String.valueOf(random.nextInt(1000000)));
Print<String, Integer> print_2_1 = new Print<String, Integer>() {
@Override
public void print(String x, Integer o) {
System.out.println(x + o);
}
};
print_2_1.print("print_2_1", 20);
Count<String> count_2_1 = new Count<String>() {
@Override
public String count() {
return String.valueOf(random.nextInt(1000000));
}
};
count_2_1.count();
}
@FunctionalInterface
interface Print<T, E> {
void print(T x, E e);
}
@FunctionalInterface
interface Count<T> {
T count();
}
}
# 编译
javac -encoding utf-8 LambdaTest.java
# 运行
java -Djdk.internal.lambda.dumpProxyClasses LambdaTest
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。