JDK 1.7 vs JDK 1.6 内部类继承差异

Posted

技术标签:

【中文标题】JDK 1.7 vs JDK 1.6 内部类继承差异【英文标题】:JDK 1.7 vs JDK 1.6 inner classes inheritance difference 【发布时间】:2016-03-07 20:07:53 【问题描述】:

我正在解决一些 Java 难题,偶然发现了这个:

public class Outer 
    class Inner1 extends Outer 
    class Inner2 extends Inner1 

在使用 javac 1.6.0_45 编译此代码时,正如预期的那样,我得到了这个错误:

Outer.java:8: cannot reference this before supertype constructor has been called
class Inner2 extends Inner1                                                                                                 
^

这是因为编译器为 Inner2 类生成了具有类似代码的默认构造函数,这解释了上面的错误:

Inner2 () 
    this.super();

现在很明显,因为在 Java 1.6.0_45、JLS 8.8.7.1 中确实无法做到这一点(我猜到了):

构造函数体中的显式构造函数调用语句可以 不引用在中声明的任何实例变量或实例方法 此类或任何超类,或在任何表达式中使用 this 或 super; 否则,会发生编译时错误。

请参阅(Odd situation for "cannot reference this before supertype constructor has been called" 中的accepted answer)

但如果我尝试用javac 1.7.0_79 编译它 - 没关系!

问题来了 - Java 1.7 中发生了什么变化,这段代码现在是正确的吗?

提前致谢!

【问题讨论】:

@EJP 你检查了那个accepted answer,因为那个看起来确实相关 @EJP,另外,this.super()等同于super()。如果您尝试在非内部非嵌套类中执行此操作,您将收到 [JLS1.6 8.8.7.1] 之前的编译时错误。 If S is not an inner class, or if the declaration of S occurs in a static context, no immediately enclosing instance of i with respect to S exists. A compiletime error occurs if the superclass constructor invocation is a qualified superclass constructor invocation. 类似于 [JLS1.7 8.8.7.1]。 【参考方案1】:

似乎在 Java 错误跟踪器上讨论了与错误 JDK-6708938: Synthetic super-constructor call should never use 'this' as a qualifier 相同的问题。

另外,我认为您最好看看上一期的其他相关问题,例如JDK-4903103: Can't compile subclasses of inner classes 。

注意两个错误的固定版本。

结果见Maintenance Review of JSR 901 (Java Language Specification) for Java SE 7。

来自The Java Language Specification Third Edition

否则,S 是内部成员类(第 8.5 节)。这是一个编译时 如果S 不是词法封闭类的成员,或者不是 超类或其超接口。让O成为最里面的词汇 S 是其成员的封闭类,让 n 为整数,例如 OC 的第 n 个词法封闭类。立即 i 相对于 S 的封闭实例在词法上是第 n 个 this 的封闭实例。

以及来自 Java SE 7 的 JSR 901(Java 语言规范)的维护审查(完整版,第 242 页,蓝色文本)或The Java Language Specification, Java SE 7 Edition 中的相同内容(就在第 8.8.8 节之前)

否则,S 是内部成员类(第 8.5 节)。

令 O 为 S 的最内层词法封闭类,令 n 为整数,使得 O 为 C 的第 n 个词法封闭类。

立即封闭 i 相对于 S 的实例是第 n 个词法封闭 这个例子。

所以你可以看到编译时错误的部分已经消失了。

【讨论】:

感谢您的回复!现在我有一个线索,肯定已经改变了!但我不明白具体是什么。在整个 8.8 部分中,我没有发现 JLS SE 7JLS Third Edition 之间有任何重大区别。 @ar4ers 我已经添加了与问题相关的这两个版本的 JSL 的差异。 非常感谢您的补充说明!现在我明白了其中的区别。而且,您可能还知道,在哪里可以找到特定的行为定义(如合成构造函数创建)?我可以猜到 - 它是 JVMS,我猜对了吗? @ar4ers 我猜你可以在 JLS(更具体的编译器)和 JVMS(更具体的运行时)中找到它。如果你想阅读它们,你可以在Java Language and Virtual Machine Specifications page找到它们【参考方案2】:

我怀疑这与 invoke dynamic 有关,它是在 java 1.7 中添加的,用于为 java 8 中的 lambda 做准备。

【讨论】:

我首先检查过它。可悲的是,事实并非如此。我在所有三个.class 文件、Outer.classOuter$Inner1.classOuter$Inner2.class 上都使用了javap -c。没有invokedynamic 的证据,只有invokespecialputfield。我目前正在调查这个问题,但还没有结果。

以上是关于JDK 1.7 vs JDK 1.6 内部类继承差异的主要内容,如果未能解决你的问题,请参考以下文章

为啥 Maven 使用 JDK 1.6 但我的 java -version 是 1.7

jdk 1.5 1.6 1.7 加入新特性

markdown 在Mac上安装卸载jdk 1.6 1.7 1.8

JDK 1.6/1.7不支持TLS 1.2

目前Java 版本是? JDK版本是?

Java切换JDK版本时遇到的小错误。