javac 生成的名称中的 $$ 是什么意思? [英] What does $$ in javac generated name mean?

查看:36
本文介绍了javac 生成的名称中的 $$ 是什么意思?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在转换由 DependencyFinder 和 java-callgraph 等库生成的 java 调用图时,我发现 java 编译器会为匿名函数、内部类等生成名称.

When shifting through java call graph generated by libraries like DependencyFinder and java-callgraph, I found out that java compiler generate names for anonymous functions, inner classes, etc.

我已经找到了其中几个的意思(如果我错了,请纠正):

I've found out the meaning of a couple of them (please correct if I'm wrong):

  • org.example.Bar$Foo指的是Foo,它是org.example.Bar的内部类.
  • org.example.Bar$1 指的是在 org.example.Bar 的方法之一中声明的匿名类.
  • org.example.Bar.lambda$spam$1() 指的是在 org.example.Bar.spam() 方法内声明的 lambda.
  • org.example.Bar$Foo refers to Foo, which is an inner class of org.example.Bar.
  • org.example.Bar$1 refers to an anonymous class declared inside one of the methods of org.example.Bar.
  • org.example.Bar.lambda$spam$1() refers to a lambda declared inside of org.example.Bar.spam() method.

然而,我也发现:

  1. org.example.Bar$$Lambda$2.args$1
  2. org.example.Bar$$Lambda$2.call()
  3. org.example.Bar$$Lambda$7.lambdaFactory$()
  4. org.example.Bar$$Lambda$7.get$Lambda()

上面的四个名字是指什么?双元 ($$) 是什么意思?

What does the four name above refer to? What does double dollar ($$) mean?

推荐答案

lambda 表达式的类不是 javac 生成的,而是由 JRE 在运行时创建的.他们的名字是完全未指定的,你不能依赖任何命名方案.

The classes for lambda expressions are not javac generated, but created at runtime by the JRE. Their names are completely unspecified and you can’t rely on any naming scheme.

但显然,Oracle 当前的 JRE 具有可识别的模式.它将 $$Lambda$n 附加到定义类的名称,而 n 是一个递增的数字,它反映了运行时创建的顺序,而不是编译代码的任何属性.

But obviously, Oracle’s current JRE has a recognizable pattern. It appends $$Lambda$n to the name of the defining class whereas n is an increasing number, which reflects the creation order at runtime, rather than any property of the compiled code.

您可以使用以下程序验证这一点:

You can verify this with the following program:

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:	"+r.getClass());
            }
            main("second run");
            if(!meFirst) {
                Runnable r=Test::main;
                System.out.println("first run:	"+r.getClass());
            }
        }
        else {
            Runnable r=Test::main;
            System.out.println(args[0]+":	"+r.getClass());
            if(args[0].equals("second run")) main("last run");
        }
    }
}

根据随机 meFirst 标志的状态,它会打印其中之一

Depending on the state of the random meFirst flag, it will print either

first run:  class Test$$Lambda$1
second run: class Test$$Lambda$2
last run:   class Test$$Lambda$2

second run: class Test$$Lambda$1
last run:   class Test$$Lambda$1
first run:  class Test$$Lambda$2

它表明第一个生成的类总是得到数字1,无论它是在第一个main调用中实例化的前两个方法引用之一还是第三个方法引用,在第一次递归中实例化.此外,第三次执行总是遇到与第二次相同的类,因为它是相同的方法引用表达式(注意:不同的表达式,因为所有表达式的目标都是相同的)并且类被重新-用过.

It shows that the first generated class always gets the number 1, regardless of whether it’s one of the first two method references instantiated in the first main invocation or the third method reference, instantiated in the first recursion. Further, the 3rd execution always encounters the same class as the 2nd, as it’s the same method reference expression (note: distinct expression, as the target of all expressions is the same) and the class is re-used.

根据版本,您可能会进一步看到类似 /number 附加到名称的内容,这暗示名称实际上并不重要,因为这些类中的每一个都有另一个唯一标识符(它们是所谓的匿名类",您无法通过 ClassLoader 和名称找到它们.

Depending on the version, you may further see something like /number appended to the names, which hints that the names really don’t matter, as each of these classes has another unique identifier (they are so called "anonymous classes" which you can’t locate via ClassLoader and name).

这些类中像 args$n 这样的字段名称代表第 n 个捕获的值.由于 LambdaMetafactory 不知道被捕获变量的实际名称,它别无选择,只能生成这样的名称.

Field names like args$n within these classes represent the n’th captured value. Since the LambdaMetafactory has no knowledge about the actual names of the captured variables, it has no other choice but to generate such names.

但如前所述,这是一个实现工件.保持这样的命名模式是可能的,只要在每个定义类中为每个创建站点生成一个新类.但由于规范允许任意共享/重用表示等效 lambda 表达式(执行相同操作)和方法引用(针对相同方法)的类和实例,因此这种命名模式并非适用于每种实现策略.

But as said, that’s an implementation artifact. It’s possible to maintain such a naming pattern, as long as a new class is generated for each creation site in each defining class. But since the specification allows arbitrary sharing/reusing of classes and instances representing equivalent lambda expressions (doing the same) and method references (targeting the same method), such a naming pattern is not possible with every implementation strategy.

这篇关于javac 生成的名称中的 $$ 是什么意思?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆