javac生成的名称中的$$是什么意思?
What does $$ in javac generated name mean?
当通过 DependencyFinder 和 java-callgraph 等库生成的 java 调用图时,我发现 java 编译器为匿名函数生成名称,内部 classes等
我找到了其中几个的意思(如有错误请指正):
org.example.Bar$Foo
指的是Foo
,是org.example.Bar
. 的内层class
org.example.Bar
指的是在 org.example.Bar
. 的方法之一中声明的匿名 class
org.example.Bar.lambda$spam()
指的是在 org.example.Bar.spam()
方法内部声明的 lambda。
不过,我还发现:
org.example.Bar$$Lambda.args
org.example.Bar$$Lambda.call()
org.example.Bar$$Lambda.lambdaFactory$()
org.example.Bar$$Lambda.get$Lambda()
以上四个名字指的是什么?双元 ($$
) 是什么意思?
lambda 表达式的 classes 不是 javac
生成的,而是由 JRE 在运行时创建的。它们的名称完全未指定,您不能依赖任何命名方案。
但显然,Oracle 当前的 JRE 具有可识别的模式。它将 $$Lambda$n
附加到定义 class 的名称,而 n
是一个递增的数字,它反映了运行时的 creation 命令,而不是任何属性 的编译代码。
您可以使用以下程序验证这一点:
public class Test {
public static void main(String... args) {
if(args.length==0) {
final boolean meFirst = Math.random()<0.5;
if(meFirst) {
Runnable r=Test::main;
System.out.println("first run:\t"+r.getClass());
}
main("second run");
if(!meFirst) {
Runnable r=Test::main;
System.out.println("first run:\t"+r.getClass());
}
}
else {
Runnable r=Test::main;
System.out.println(args[0]+":\t"+r.getClass());
if(args[0].equals("second run")) main("last run");
}
}
}
根据随机meFirst
标志的状态,它会打印
first run: class Test$$Lambda
second run: class Test$$Lambda
last run: class Test$$Lambda
或
second run: class Test$$Lambda
last run: class Test$$Lambda
first run: class Test$$Lambda
它表明第一个生成的 class 总是得到数字 1
,无论它是第一个 main
调用中实例化的前两个方法引用之一还是第三个方法引用,在第一次递归中实例化。此外,第 3 次执行总是遇到与第 2 次相同的 class,因为它是相同的方法引用表达式(注意:distinct expression,因为所有表达式的目标都是相同的) 并且 class 被重新使用。
根据版本的不同,您可能会进一步看到类似 /number
的内容附加到名称中,这暗示名称实际上并不重要,因为每个 classes 都有另一个独特的标识符(它们被称为“匿名 classes”,您无法通过 ClassLoader
和名称找到它)。
这些 class 中的 args$n
等字段名称表示第 n 个捕获的值。由于 LambdaMetafactory
不知道捕获变量的实际名称,因此别无选择,只能生成此类名称。
但如前所述,这是一个实现工件。只要在每个定义class中为每个创建站点生成一个新的class,就可以保持这样的命名模式。但是由于规范允许任意 sharing/reusing 的 classes 和实例表示等效的 lambda 表达式(做同样的事情)和方法引用(针对相同的方法),这样的命名模式并不是每个实现策略都可能的.
当通过 DependencyFinder 和 java-callgraph 等库生成的 java 调用图时,我发现 java 编译器为匿名函数生成名称,内部 classes等
我找到了其中几个的意思(如有错误请指正):
org.example.Bar$Foo
指的是Foo
,是org.example.Bar
. 的内层class
org.example.Bar
指的是在org.example.Bar
. 的方法之一中声明的匿名 class
org.example.Bar.lambda$spam()
指的是在org.example.Bar.spam()
方法内部声明的 lambda。
不过,我还发现:
org.example.Bar$$Lambda.args
org.example.Bar$$Lambda.call()
org.example.Bar$$Lambda.lambdaFactory$()
org.example.Bar$$Lambda.get$Lambda()
以上四个名字指的是什么?双元 ($$
) 是什么意思?
lambda 表达式的 classes 不是 javac
生成的,而是由 JRE 在运行时创建的。它们的名称完全未指定,您不能依赖任何命名方案。
但显然,Oracle 当前的 JRE 具有可识别的模式。它将 $$Lambda$n
附加到定义 class 的名称,而 n
是一个递增的数字,它反映了运行时的 creation 命令,而不是任何属性 的编译代码。
您可以使用以下程序验证这一点:
public class Test {
public static void main(String... args) {
if(args.length==0) {
final boolean meFirst = Math.random()<0.5;
if(meFirst) {
Runnable r=Test::main;
System.out.println("first run:\t"+r.getClass());
}
main("second run");
if(!meFirst) {
Runnable r=Test::main;
System.out.println("first run:\t"+r.getClass());
}
}
else {
Runnable r=Test::main;
System.out.println(args[0]+":\t"+r.getClass());
if(args[0].equals("second run")) main("last run");
}
}
}
根据随机meFirst
标志的状态,它会打印
first run: class Test$$Lambda
second run: class Test$$Lambda
last run: class Test$$Lambda
或
second run: class Test$$Lambda
last run: class Test$$Lambda
first run: class Test$$Lambda
它表明第一个生成的 class 总是得到数字 1
,无论它是第一个 main
调用中实例化的前两个方法引用之一还是第三个方法引用,在第一次递归中实例化。此外,第 3 次执行总是遇到与第 2 次相同的 class,因为它是相同的方法引用表达式(注意:distinct expression,因为所有表达式的目标都是相同的) 并且 class 被重新使用。
根据版本的不同,您可能会进一步看到类似 /number
的内容附加到名称中,这暗示名称实际上并不重要,因为每个 classes 都有另一个独特的标识符(它们被称为“匿名 classes”,您无法通过 ClassLoader
和名称找到它)。
这些 class 中的 args$n
等字段名称表示第 n 个捕获的值。由于 LambdaMetafactory
不知道捕获变量的实际名称,因此别无选择,只能生成此类名称。
但如前所述,这是一个实现工件。只要在每个定义class中为每个创建站点生成一个新的class,就可以保持这样的命名模式。但是由于规范允许任意 sharing/reusing 的 classes 和实例表示等效的 lambda 表达式(做同样的事情)和方法引用(针对相同的方法),这样的命名模式并不是每个实现策略都可能的.