public class OuterChild extends OuterChild.InnerParent { public static class InnerParent { } }
无法编译:
$javac OuterChild.java OuterChild.java:1: error: cyclic inheritance involving OuterChild public class OuterChild extends OuterChild.InnerParent { ^ 1 error
因为OuterChild将“依赖”本身,因为(每个§8.1.4 “Superclasses and Subclasses” of The Java Language Specification,Java SE 8 Edition)一个类直接依赖于“在它的扩展或者实现子句[…]中被提到的任何类型作为超类或超级接口名称的完全限定形式的限定符“.
但我不太明白这里的动机.什么是有问题的依赖性?这是否只是为了与InnerParent非静态(因此最终会包含本身的词汇封闭实例)的情况保持一致?
解决方法
This example is not legal,and this is made clear in the forthcoming
2nd edition of the Java Language Specification. Classes simultaneously
related by both inheritance and enclosure are problematical,however
the original innerclasses whitepaper did not adequately address the issue,
nor did the pre-1.3 compilers implement a consistent policy. In JLS 2nd
edition,the rule against cyclic inheritance has been extended to prohibit
a class or interface from “depending” on itself,directly or indirectly.
A type depends not only on types that it extends or implements,but also on
types that serve as qualifiers within the names of those types.
The two class declarations are indeed cyclic; accordingly to JLS 8.1.4 we have that:
Foo depends on Foo$Intf (Foo$Intf appears in the implements clause of Foo)
Foo$Intf depends on Moo$Intf (Moo$Intf appears in the extends clause of Foo$Intf)
Foo$Intf depends on Foo (Foo appears as a qualifier in the extends clause of Foo$Intf)For transitivity,we have that Foo depends on itself; as such the code should be rejected with a compile-time error.
Stepping back,the directly-depends relationship for classes and interfaces was introduced in JLS2 to clarify JLS1 and to cover superclasses/superinterfaces that are nested classes (e.g. A.B in the Description).
This problem is due to the order in which javac perform attribution of type-variable bounds wrt class attribution.
1) Attribution of class Outer<T extends Outer.Inner>
1a) Attribution of Outer triggers attribution of Outer’s type variable
2) Attribution of Outer.T
2a) Attribution of Outer.T triggers attribution of its declared bound
3) Attribution of class Outer.Inner<S extends T>
3a) Attribution of Outer.Inner triggers attribution of Outer.Inner’s type variable
4) Attribution of Outer.Inner<S>
4a) Attribution of Outer.Inner.S triggers attribution of its declared bound
5) Attribution of Outer.T – this does nothing but returning the type of T; as you can see,at this stage T’s bound has not been set yet on the object representing the type of T.At a later point,for each attributed type variable,javac performs a check to ensure that the bound of a given type variable does not introduce cyclic inheritance. But we have seen that no bound is set for Outer.T; for this is the reason javac crashes with a NPE when trying to detect a cycle in the inheritance tree induced by the declared bound of Outer.Inner.S.
Type-variable bounds might refer to classes belonging to a cyclic inheritance tree which causes the resolution process to enter a loop when looking up for symbols.
对于你的具体问题“什么是有问题的依赖性”?它似乎是一个复杂的编译时符号解析边缘案例,JLS2中引入的解决方案是简单地禁止限定符类型以及实际超类引入的循环.
换句话说,理论上这可以使编译器得到适当的改进,但是直到有人出现并发生这种情况,才能在语言规范中禁止这种不寻常的关系.