package com.test;
public class OuterClass {
public class InnerClass {
public class InnerInnerClass {
}
}
public class InnerClass2 {
}
//this class should not exist in OuterClass after dummifying
private class PrivateInnerClass {
private String getString() {
return "hello PrivateInnerClass";
}
}
public String getStringFromPrivateInner() {
return new PrivateInnerClass().getString();
}
}
当使用 Sun JVM 1.6.0_20
在命令行上运行 javac
时,此代码会生成 6 个 .class 文件:
OuterClass.class
OuterClass$1.class
OuterClass$InnerClass.class
OuterClass$InnerClass2.class
OuterClass$InnerClass$InnerInnerClass.class
OuterClass$PrivateInnerClass.class
当在 eclipse 中运行 JDT 时,它只生成 5 个类。
OuterClass.class
OuterClass$1.class
OuterClass$InnerClass.class
OuterClass$InnerClass2.class
OuterClass$InnerClass$InnerInnerClass.class
OuterClass$PrivateInnerClass.class
反编译时,OuterClass$1.class
不包含任何内容。这个额外的类从哪里来,为什么要创建它?
最佳答案
我正在使用 Polygenelubricants 的较小片段。
请记住,字节码中没有嵌套类的概念;然而,字节码知道访问修饰符。编译器试图在这里规避的问题是
方法instantiate()
需要创建PrivateInnerClass
的新实例。但是,OuterClass
无法访问 PrivateInnerClass
的构造函数(OuterClass$PrivateInnerClass
将生成为没有公共(public)构造函数的包保护类)。
那么编译器能做什么呢?显而易见的解决方案是更改 PrivateInnerClass
以具有受包保护的构造函数。这里的问题是,这将允许与该类交互的任何其他代码创建 PrivateInnerClass
的新实例,即使它被显式声明为私有(private)!
为了尝试防止这种情况,javac 编译器做了一个小技巧:它不是让 PrivateInnerClass
的常规构造函数对其他类可见,而是将其隐藏(实际上它根本没有定义它,但从外部看也是一样的)。相反,它创建一个新的构造函数,该构造函数接收特殊类型 OuterClass$1
的附加参数。
现在,如果您查看 instantiate()
,它会调用新的构造函数。它实际上发送 null
作为第二个参数(类型为 OuterClass$1
) - 该参数仅用于指定应调用此构造函数。
那么,为什么要为第二个参数创建一个新类型呢?为什么不使用Object
呢?它仅用于将其与常规构造函数区分开来,并且 null
无论如何都会被传递!答案是,由于 OuterClass$1
是 OuterClass 私有(private)的,合法的编译器永远不会允许用户调用特殊的 OuterClass$PrivateInnerClass
构造函数,因为所需的参数类型之一 OuterClass$1
被隐藏了。
我猜测 JDT 的编译器使用另一种技术来解决同样的问题。
关于java - 为什么此代码生成的匿名内部类不包含任何内容?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30824861/