rua*_*akh 10 java inner-classes language-lawyer
这个班:
public class OuterChild extends OuterChild.InnerParent {
public static class InnerParent {
}
}
Run Code Online (Sandbox Code Playgroud)
无法编译:
$ javac OuterChild.java
OuterChild.java:1: error: cyclic inheritance involving OuterChild
public class OuterChild extends OuterChild.InnerParent {
^
1 error
Run Code Online (Sandbox Code Playgroud)
因为OuterChild"依赖于"本身,因为(根据Java语言规范,Java SE 8版的§8.1.4"超类和子类")一个类直接依赖于[在] [ extends或] implements子句中提到的任何类型[... ]作为超类或超界面名称的完全限定形式的限定符."
但我真的不明白这里的动机.什么是有问题的依赖?它只是为了与InnerParent非的情况保持一致static(并因此最终得到一个词汇封闭的实例)?
这似乎是一个相当邪恶的角落,因为存在许多与循环继承相关的错误,通常导致编译器中的无限循环,堆栈溢出和OOM.以下是一些可能提供一些见解的相关报价:
这个例子是不合法的,这在即将出版的第二版Java语言规范中已经明确了.同时通过继承和封闭相关的类是有问题的,但是原始的内部类白皮书没有充分解决该问题,1.3之前的编译器也没有实现一致的策略.在JLS第2版中,针对循环继承的规则已经扩展到禁止类或接口直接或间接地"依赖"它自身.类型不仅取决于它扩展或实现的类型,还取决于在这些类型的名称中充当限定符的类型.
这两个类声明确实是循环的; 相应于JLS 8.1.4,我们有:
Foo依赖于Foo $ Intf(Foo $ Intf出现在Foo的implements子句中)
Foo $ Intf依赖于Moo $ Intf(Moo $ Intf出现在Foo $ Intf的extends子句中)
Foo $ Intf取决于Foo(Foo出现为Foo $ Intf的extends子句中的限定符对于传递性,我们认为Foo依赖于自身; 因此,代码应该被编译时错误拒绝.
退一步,在JLS2中引入了类和接口的直接依赖关系,以阐明JLS1并涵盖作为嵌套类的超类/超接口(例如,描述中的AB).
这个问题是由于javac执行类型变量边界归因于类属性的顺序.
1)类Outer <T的归属延伸Outer.Inner>
1a)外部的归因触发外部类型变量的
归属2)外部的归因.T
2a)外部的归因.T触发其声明边界的归属
3)类外部的归因.Inner <S extends T>
3a)Outer.Inner的归因触发Outer.Inner的类型变量的
归因4)Outer.Inner的归因
4a)Outer.Inner.S的归因触发其声明的界限
归因5)归因Outer.T - 这只会返回T的类型; 正如你所看到的,在这个阶段T的绑定还没有设置在代表T类型的对象上.稍后,对于每个属性类型变量,javac执行检查以确保给定类型变量的边界不引入循环继承.但我们已经看到Outer.T没有设定界限; 因为这是javac在尝试检测由Outer.Inner.S声明的边界引起的继承树中的循环时与NPE崩溃的原因.
类型变量边界可能引用属于循环继承树的类,这会导致解析过程在查找符号时进入循环.
对于你的具体问题" 什么是有问题的依赖? "它似乎是一个复杂的编译时符号解析边缘情况,JLS2中引入的解决方案是简单地禁止由限定符类型和实际超类型引入的循环.
换句话说,理论上可以对编译器进行适当的改进,但是在有人出现并实现这一点之前,在语言规范中禁止这种不寻常的关系更为实际.
| 归档时间: |
|
| 查看次数: |
852 次 |
| 最近记录: |