class 文件在文件系统上的含义
Meaning of class file on the file system
我正在学习 lambda 表达式,这本书说明了一个使用 toString()
lambda 表达式方法的示例。
Supplier<ArrayList<String>> s1 = ArrayList<String>::new;
ArrayList<String> a1 = s1.get();
System.out.println(s1);
//Output: functionalinterface.BuiltIns$$Lambda/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.
最后几句的意思我没看懂。你能表达出来吗?
When you create a class, you type out a .java
file and compile it to a
.class
file. Both are actual files that exist somewhere on your
filesystem. The $$
shows it is different. There is no .java class
on
the filesystem. Instead Java creates the class for us. That way you
don't have to type out a class and can just supply the lambda
expression.
作者回答,Ms.Boyarsky
嗯,这本书有点误导。该声明确实正确,但有一个小的更正。它 假定 如果您在 class 名称中包含 $
,它将自动创建(不是由您创建);这可能不是事实。
例如假设这个例子:
public class TestSO {
public static void main(String[] args) {
Test t = new Test() {
};
}
static class Test {}
}
您创建了一个匿名内部 class,它实际上是由编译器创建的普通 class。如果您编译 TestSO
,您将看到一个名为 TestSO$1.class
的 class,它是为您创建的。如果你用 javap -c -p TestSO$1.class
检查它的外观,你会看到这样的东西:
final class TestSO extends TestSO$Test { ...
但是同时声明一个包含$
符号的class/method是完全合法的:
static class $$Test2$$ {}
因此 $$
的存在并不强烈表明 class 是由 compiler/runtime 生成的。这也是一个实施细节,有一天可能会改变......
同时这本书是正确的 the class doesn’t exist in a class file on the file system. It exists only in memory
.
Supplier
是一个接口,您还没有提供实现它的 class,是吗?那么接下来发生的事情很有趣。
我不打算详细介绍,但这里有一个简化的解释。
如果你反编译你的例子(javap -p -c -v TestSO.class
)你会看到这样一行:
invokedynamic #2, 0 // InvokeDynamic #0:get:()Ljava/util/function/Supplier;
invokedynamic
所做的是让 runtime
决定如何提供 Supplier
的实际实例。 在运行时创建了一个实际的class来实现所使用的Supplier
。
你可以看到 class 看起来像 运行 时使用的命令:
-Djdk.internal.lambda.dumpProxyClasses=/Your/Path/Here
因此在该路径中您将看到一个 class 名为:
TestSO$$Lambda.class
再一次,如果你用 javap -c -p TestSO$$Lambda$1.class
反编译它:
final class TestSO$$Lambda
implements java.util.function.Supplier {....
作者想说的是,在运行时会为你生成一个class
实现了Supplier接口,但不是你创建的。
这个引用是试图用更简单或更口语化的术语来解释一些事情,避免过于正式,但是,结果可以说是灾难性的。
这个名字实际上没有任何意义。为 lambda 表达式或方法引用提供的实例的 class is intentionally unspecified 及其名称也是如此。甚至未指定在执行 System.out.println(s1);
时隐式调用的 toString()
方法是否会产生“classname@hashcode”输出。
是否涉及文件系统无关紧要。正确和实际的一点是,在编译应用程序时,该实例的 class 不在 Java 编译器创建的 classes 中。相反,它由 JRE 在运行时以特定于实现的方式提供。 OpenJDK 确实提供了一个生成的 class,它恰好有一个包含包含 lambda 表达式的 class 和一个 $$
的名称,但是,如前所述,这是一个实现细节。而且,,美元符号是 Java 标识符的合法部分,因此两个美元符号的存在并不能证明特定的 属性.
我正在学习 lambda 表达式,这本书说明了一个使用 toString()
lambda 表达式方法的示例。
Supplier<ArrayList<String>> s1 = ArrayList<String>::new;
ArrayList<String> a1 = s1.get();
System.out.println(s1);
//Output: functionalinterface.BuiltIns$$Lambda/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.
最后几句的意思我没看懂。你能表达出来吗?
When you create a class, you type out a
.java
file and compile it to a.class
file. Both are actual files that exist somewhere on your filesystem. The$$
shows it is different. There is no.java class
on the filesystem. Instead Java creates the class for us. That way you don't have to type out a class and can just supply the lambda expression.
作者回答,Ms.Boyarsky
嗯,这本书有点误导。该声明确实正确,但有一个小的更正。它 假定 如果您在 class 名称中包含 $
,它将自动创建(不是由您创建);这可能不是事实。
例如假设这个例子:
public class TestSO {
public static void main(String[] args) {
Test t = new Test() {
};
}
static class Test {}
}
您创建了一个匿名内部 class,它实际上是由编译器创建的普通 class。如果您编译 TestSO
,您将看到一个名为 TestSO$1.class
的 class,它是为您创建的。如果你用 javap -c -p TestSO$1.class
检查它的外观,你会看到这样的东西:
final class TestSO extends TestSO$Test { ...
但是同时声明一个包含$
符号的class/method是完全合法的:
static class $$Test2$$ {}
因此 $$
的存在并不强烈表明 class 是由 compiler/runtime 生成的。这也是一个实施细节,有一天可能会改变......
同时这本书是正确的 the class doesn’t exist in a class file on the file system. It exists only in memory
.
Supplier
是一个接口,您还没有提供实现它的 class,是吗?那么接下来发生的事情很有趣。
我不打算详细介绍,但这里有一个简化的解释。
如果你反编译你的例子(javap -p -c -v TestSO.class
)你会看到这样一行:
invokedynamic #2, 0 // InvokeDynamic #0:get:()Ljava/util/function/Supplier;
invokedynamic
所做的是让 runtime
决定如何提供 Supplier
的实际实例。 在运行时创建了一个实际的class来实现所使用的Supplier
。
你可以看到 class 看起来像 运行 时使用的命令:
-Djdk.internal.lambda.dumpProxyClasses=/Your/Path/Here
因此在该路径中您将看到一个 class 名为:
TestSO$$Lambda.class
再一次,如果你用 javap -c -p TestSO$$Lambda$1.class
反编译它:
final class TestSO$$Lambda
implements java.util.function.Supplier {....
作者想说的是,在运行时会为你生成一个class
实现了Supplier接口,但不是你创建的。
这个引用是试图用更简单或更口语化的术语来解释一些事情,避免过于正式,但是,结果可以说是灾难性的。
这个名字实际上没有任何意义。为 lambda 表达式或方法引用提供的实例的 class is intentionally unspecified 及其名称也是如此。甚至未指定在执行 System.out.println(s1);
时隐式调用的 toString()
方法是否会产生“classname@hashcode”输出。
是否涉及文件系统无关紧要。正确和实际的一点是,在编译应用程序时,该实例的 class 不在 Java 编译器创建的 classes 中。相反,它由 JRE 在运行时以特定于实现的方式提供。 OpenJDK 确实提供了一个生成的 class,它恰好有一个包含包含 lambda 表达式的 class 和一个 $$
的名称,但是,如前所述,这是一个实现细节。而且,