编译器是在运行时还是提前创建匿名Java类?
根据Java文档They are like local classes except that they do not have a name
,所以我的猜测是它们是提前创建的。如果您能引用您的来源或知道如何测试这样的事情,请告诉我!
答案 0 :(得分:11)
它们是由编译器创建的。您只需编译一些代码并查看磁盘上的内容即可看到它们。您最终会得到像Foo$1.class
这样的内容,其中Foo
是包含匿名方法的类。
例如:
public class Test {
public static void main(String[] args) {
Runnable runnable = new Runnable() {
@Override public void run() {
System.out.println("Hi");
}
};
}
}
> javac Test.java
> dir Test*.class
Test.class
Test$1.class
> javap -c Test$1
Compiled from "Test.java"
final class Test$1 implements java.lang.Runnable {
Test$1();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public void run();
Code:
0: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #3 // String Hi
5: invokevirtual #4 // Method java/io/PrintStream.println[...]
8: return
}
就JVM而言,它们只是普通的类。编译器添加的各种语言功能,例如相关的编码实例,是通过额外的方法,构造函数参数和通过使用您无法引用的名称而有效隐藏的字段实现的。
并不是说生成的类没有名称,实际上 - 它只是一个强烈不鼓励手动代码的名称。来自JLS 3.8:
“Java字母”包括大写和小写ASCII拉丁字母AZ(\ u0041- \ u005a)和az(\ u0061- \ u007a),并且由于历史原因,ASCII下划线(_或\ u005f)和美元符号($,或\ u0024)。 $符号应仅用于机械生成的源代码,或者很少用于访问旧系统上预先存在的名称。
所以理论上你可以访问源代码中的Test$1
- 但javac
似乎阻止你这样做,我还没有理解。 (我认为它使用类文件中的元数据来检查它是否是从匿名内部类编译的。)这使得它从语言角度“或多或少”匿名。
答案 1 :(得分:4)
匿名类的字节代码是在编译时创建的。只需检查已编译的类文件即可确认。匿名类以其封闭类命名,后跟$
符号和越来越多的数字。