Lambda 类文件在文件系统中的意义
我正在研究lambda表达式,这本书举例说明了使用lambda表达式的Lambda 类文件在文件系统中的意义,lambda,java-8,method-reference,Lambda,Java 8,Method Reference,我正在研究lambda表达式,这本书举例说明了使用lambda表达式的toString()方法 Supplier<ArrayList<String>> s1 = ArrayList<String>::new; ArrayList<String> a1 = s1.get(); System.out.println(s1); //Output: functionalinterface.BuiltIns$$Lambda$1/791452441@1fb3e
toString()
方法
Supplier<ArrayList<String>> s1 = ArrayList<String>::new;
ArrayList<String> a1 = s1.get();
System.out.println(s1);
//Output: functionalinterface.BuiltIns$$Lambda$1/791452441@1fb3ebeb
供应商
创建类时,键入.java
文件并将其编译为
.class
文件。这两个文件都是存在于计算机上某个位置的实际文件
文件系统。$$
显示它是不同的。上没有.java类
文件系统。相反,Java为我们创建了类。那样你
不必键入类,只需提供lambda即可
表情
作者回答说,这本书有点误导人。这句话确实正确,但稍加更正。它假设如果类名称中有$
,则会自动创建(不是由您创建);这可能不是事实
例如,假设以下示例:
public class TestSO {
public static void main(String[] args) {
Test t = new Test() {
};
}
static class Test {}
}
您已经创建了一个匿名内部类,它实际上是由编译器创建的普通类。如果编译TestSO
,您将看到为您创建的名为TestSO\$1.class
的类。如果您使用javap-c-p TestSO\$1.class
检查它的外观,您将看到如下内容:
final class TestSO$1 extends TestSO$Test { ...
invokedynamic #2, 0 // InvokeDynamic #0:get:()Ljava/util/function/Supplier;
但同时,声明包含$
符号的类/方法是完全合法的:
static class $$Test2$$ {}
因此,$
的存在并不能强烈地表明该类是由编译器/运行时生成的。另外,这是一个可能有一天会改变的实施细节
同时,这本书是正确的,因为类不存在于文件系统的类文件中。它只存在于内存中
Supplier
是一个接口,您还没有提供实现它的类,是吗?接下来发生的事情很有趣
我不打算讲太多细节,但这里有一个简单的解释
如果您反编译您的示例(javap-p-c-vtestso.class
),您将看到如下一行:
final class TestSO$1 extends TestSO$Test { ...
invokedynamic #2, 0 // InvokeDynamic #0:get:()Ljava/util/function/Supplier;
invokedynamic
所做的是让运行时
决定如何提供该供应商的实际实例。而在运行时创建了一个实际的类,该类实现了所使用的Supplier
您可以通过运行该类时使用的命令查看该类的外观:
-Djdk.internal.lambda.dumpProxyClasses=/Your/Path/Here
因此,在该路径中,您将看到一个名为:
TestSO$$Lambda$1.class
同样,如果使用javap-c-ptestso\$\$Lambda\$1.class对其进行反编译:
final class TestSO$$Lambda$1
implements java.util.function.Supplier {....
作者想说的是,在运行时会为您生成一个实现供应商接口的类,但不是您创建的 这篇引文试图用更简单或更通俗的术语来解释某些事情,避免过于正式,然而,结果可能被称为灾难性的
这个名字实际上毫无意义。为lambda表达式或方法引用提供的实例类及其名称。甚至还未确定执行System.out.println(s1)时是否隐式调用了toString()
方法代码>将生成“classname@hashcode“产出
无论是否涉及文件系统,都是无关紧要的。正确且实际的一点是,在编译应用程序时,该实例的类不在Java编译器创建的类中。相反,它是由JRE在运行时以特定于实现的方式提供的。OpenJDK确实提供了一个生成的类,该类的名称恰好包含包含lambda表达式的类和一个$$
,但正如前面所说,这是一个实现细节。而且,美元符号是Java标识符的合法部分,因此两个美元符号的存在并不能证明是一个特定的属性。谢谢你,大师。它满足了我的期望,而不是一半。顺便说一句,我喜欢读你的答案。这就是为什么它被称为匿名:)