我正在研究 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@1fb3ebeb
它将输出的含义解释为,
This actually does mean something. Our test class is named BuiltIns , and it is in a package that we created named functionalinterface . Then comes
$$
, which means that the class doesn’t exist in a class file on the file system. It exists only in memory.
最后几句的意思没看懂。你能表达出来吗?
最佳答案
好吧,这本书有点误导。该声明确实正确,但有一个小的更正。它假设如果您在类名中包含$
,它会自动创建(不是由您创建);这可能不是事实。
例如假设这个例子:
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 { ...
但是同时声明包含$
符号的类/方法是完全合法的:
static class $$Test2$$ {}
因此 $$
的存在并不强烈表明该类是由编译器/运行时生成的。这也是一个实现细节,有一天可能会改变......
同时这本书是正确的,类不存在于文件系统的类文件中。它只存在于内存中
。
Supplier
是一个接口(interface),您还没有提供实现它的类,是吗?那么接下来发生的事情很有趣。
我不打算详细介绍,但这里有一个简化的解释。
如果反编译您的示例 (javap -p -c -v TestSO.class
),您将看到如下一行:
invokedynamic #2, 0 // InvokeDynamic #0:get:()Ljava/util/function/Supplier;
invokedynamic
所做的是让runtime
决定如何提供该Supplier
的实际实例。 在运行时会创建一个实际类来实现所使用的Supplier
。
您可以通过运行它时使用的命令来查看该类的外观:
-Djdk.internal.lambda.dumpProxyClasses=/Your/Path/Here
作为该路径的结果,您将看到一个名为的类:
TestSO$$Lambda$1.class
再次,如果您使用 javap -c -p TestSO\$\$Lambda\$1.class
反编译它:
final class TestSO$$Lambda$1
implements java.util.function.Supplier {....
作者想说的是,在运行时会为您生成一个类
,它实现了Supplier 接口(interface),但它不是您创建的。
关于lambda - 类文件在文件系统中的含义,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44475789/