这似乎是一个非常有害的极端情况,因为存在许多与循环继承相关的错误,这些错误通常导致编译器中出现无限循环,堆栈溢出和OOM。以下是一些可能提供一些见解的相关报价:
这个例子是 不 合法的,在即将出版的第二版Java语言规范中对此做了明确说明。通过继承和封闭性同时关联的类是有问题的,但是原始的内部类白皮书并未充分解决该问题,1.3之前的编译器也未实施一致的策略。在JLS 2nd Edition中,扩展了禁止循环继承的规则,以禁止类或接口直接或间接“依赖”自身。一个类型不仅取决于它扩展或实现的类型,还取决于那些类型名称中充当限定符的类型。
这两个类的声明确实是循环的。根据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执行wrt类归因的类型变量范围归因的顺序。
1)类Outer
3a)Outer的归属.Inner触发Outer.Inner的类型变量的 归属4)Outer.Inner
的 归属4a)Outer.Inner.S的归属触发其声明的绑定的归属 5)归属of Outer.T-除了返回T的类型外什么也不做;如您所见,在此阶段,尚未在表示T类型的对象上设置T的界限。
稍后,对于每个属性类型变量,javac都会执行检查以确保给定类型变量的边界不会引入循环继承。但是我们已经看到,Outer.T没有设置任何限制。因此,这是javac在尝试检测由Outer.Inner.S的已声明边界引起的继承树中的循环时因NPE崩溃的原因。
类型变量界限可能是指属于循环继承树的类,当查询符号时,此类会导致解析过程进入循环。
对于您的“ 问题依赖性是什么? ”这个特定问题,这似乎是一个复杂的编译时符号解析边缘情况,并且JLS2中引入的解决方案是简单地禁止限定符类型以及实际超类型引入的循环。
换句话说,从理论上讲,可以对编译器进行适当的改进,但是直到有人出现并实现这种情况时,在语言规范中禁止这种不寻常的关系才更实际。