在JShell中,如果我这样做:
interface Foo { String foo(); }
(Foo) () -> "hi"
我得到
| created interface Foo
$2 ==> $Lambda$15/0x00000008000a9440@32e6e9c3
从下面的研究中,我知道了以下几点:
$λ = an in-memory reference, as opposed to one persisted to disk by an anonymous inner class (AIC), to the generated bytecode
$15 =对AIC的对象引用
@32e6e9c3 =所创建对象的序列号--至少在IntelliJ中是这样
但是,/
(斜线)表示什么,例如/0x00000008000a9440
?
1条答案
按热度按时间zsohkypk1#
总结
$Lambda$15/0x00000008000a9440
是创建的隐藏类的名称。如下所示,
0x00000008000a9440
被称为后缀。类的名称可以通过调用
java.lang.Class.getName()
方法来检索。因此:显示隐藏类名称的示例程序
Program
类程序输出
文档参考
JEP 371:隐藏类
隐藏类是从JDK 15开始引入的。有关其他详细信息,请参阅JEP:JEP 371: Hidden Classes。
下面是从JEP中摘录的有关隐藏类名的内容:
隐藏类创建方式的主要区别在于它的名称。**隐藏类不是匿名的。**它有一个可通过
Class::getName
获得的名称,并可能在诊断中显示(例如java -verbose:class
的输出)、在JVM TI类加载事件中、在JFR事件中以及在堆栈跟踪中。但是,这个名字有一个非常不寻常的形式,它有效地使这个类对所有其他类不可见。2这个名字是以下内容的连接:1.由
ClassFile
结构中的this_class
指定的内部形式(JVMS 4.2.1)的二进制名称,例如A/B/C
;'.'
字符;和1.由JVM实现选择的非限定名称(JVMS 4.2.2)。
例如,如果
this_class
指定com/example/Foo
(二进制名称com.example.Foo
的内部形式),则从ClassFile
结构衍生的隐藏类别可能会命名为com/example/Foo.1234
。这个字串既不是二进制名称,也不是二进制名称的内部形式。给定一个名为
A/B/C.x
的隐藏类,Class::getName
的结果是以下内容的串联:1.二进制名称
A.B.C
(通过取A/B/C
并将每个'/'
替换为'.'
来获得);1.“/”字符;和
1.不合格名称
x
。例如,如果隐藏类别的名称为
com/example/Foo.1234
,则Class::getName
的结果为com.example.Foo/1234
。同样,这个字串既不是二进制名称,也不是二进制名称的内部形式。给定
ClassFile
结构,其中this_class
指定com/example/Foo/1234
,调用cl.defineClass("com.example.Foo.1234", bytes, ...)
只会产生名为com.example.Foo.1234
的普通类,与名为com.example.Foo/1234
的隐藏类不同。不可能创建名为com.example.Foo/1234
的普通类,因为cl.defineClass("com.example.Foo/1234", bytes, ...)
将拒绝字符串参数,因为它不是二进制名称。Javadoc:
java.lang.Class#getName()
方法让我们参考方法文档:类(Java SE 15和JDK 15)。
文档摘录:
公共String获取名称()
返回此
Class
对象表示的实体(类、接口、数组类、基元类型或void)的名称。如果此
Class
对象表示类或接口,而不是数组类,则:N + '/' + <suffix>
,其中N
是由传递给Lookup::defineHiddenClass
的class
文件指示的二进制名称,<suffix>
是非限定名称。实施细节:OpenJDK Java虚拟机:隐藏的类名
简介
让我们考虑一下OpenJDK 18的源代码。
让我们参考标记:openjdk/jdk18 at jdk-18+37。
请注意:
18.0.1-ea+10-Debian-1
。隐藏的类名损坏
隐藏类的创建(
java.lang.invoke.MethodHandles.Lookup.defineHiddenClass()
方法)包括其名称的修改。让我们考虑下面的调用堆栈:
然后,让我们将下面的执行路径视为调用堆栈的延续:
让我们参考这段源代码:在jdk-18+37上的jdk18/classFileParser.cpp文件解析器.打开jdk/jdk 18:
请注意,
+
字符用作分隔符。获取隐藏类名
java.lang.Class#getName()
方法包括字符替换:+
已替换为/
。让我们考虑以下执行路径:
让我们参考这段源代码:在jdk-18+37上的jdk18/klass.cpp.打开jdk/jdk 18: