java - 为什么此代码生成的匿名内部类不包含任何内容?

标签 java inner-classes anonymous-class

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/

相关文章:

java - 如何从 Guava 集合中更改 ImmutableSet?

java - 如何在用户请求的特定日期和时间运行一组特定的java代码

c++ - 为类模板的特定嵌套类实现非成员泛型函数

java - 在运行时更改类结构或将其放入匿名类中

java - setOnCheckedChangeListener 参数

java - 自动将长行的 Java 代码重新格式化为 80 列并仍然可以编译?

java - 使用 Java 多线程实现交通信号

scala - 当扩展特征中的特征时, 'super' 指的是什么?

ios - 在模型中快速使用内部类是一种好习惯吗?

.net - 有没有办法将动态或匿名对象转换为强类型的声明对象?