为什么类不能扩展其中出现的静态嵌套类? [英] Why can't a class extend a static nested class occurring within it?

查看:131
本文介绍了为什么类不能扩展其中出现的静态嵌套类?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

此类:

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 Java语言规范,Java SE 8 Edition的超类和子类一类直接依赖于提到的任何类型 [its] extends implements clause […]作为超类或超接口的完全限定形式的限定符名字。

because OuterChild would "depend on" itself, because (per §8.1.4 "Superclasses and Subclasses" of The Java Language Specification, Java SE 8 Edition) a class directly depends on any type that "is mentioned in [its] extends or implements clause […] as a qualifier in the fully qualified form of a superclass or superinterface name."

但我真的没有了解这里的动机。什么是有问题的依赖?它只是为了与 InnerParent 是非 - static 的情况保持一致(因此最终将以词汇方式封闭本身的实例)?

But I don't really understand the motivation here. What is the problematic dependency? Is it just for consistency with the case where InnerParent were non-static (and would therefore end up with a lexically enclosing instance of itself)?

推荐答案

这似乎是一个相当邪恶的角落案例,因为有一个与循环继承相关的错误数量,通常会导致无限循环,堆栈溢出和编译器中的OOM。以下是一些可能提供一些见解的相关报价:

This appears to be a fairly nefarious corner-case, as there are a number of bugs related to cyclic inheritance, often leading to infinite loops, stack overflows, and OOMs in the compiler. Here are some relevant quotes that may offer some insight:

错误4326631


此示例合法,并且这在Java语言规范的即将发布的
第2版中已经明确了。继承和封闭相关的类同时
是有问题的,但是原始内部白皮书的b $ b没有充分解决问题,
也没有1.3之前的编译器实现一致的策略。在JLS 2nd
版本中,针对循环继承的规则已被扩展为禁止
类或接口直接或间接地依赖自身。
类型不仅取决于它扩展或实现的类型,还取决于
类型,它们在这些类型的名称中用作限定符。

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.

错误6695838


这两个类声明确实是循环的;相应于JLS 8.1.4我们有:

The two class declarations are indeed cyclic; accordingly to JLS 8.1.4 we have that:

Foo取决于Foo $ Intf(Foo $ Intf出现在Foo的implements子句中)

Foo $ Intf取决于Moo $ Intf(Moo $ Intf出现在Foo $ Intf的extends子句中)

Foo $ Intf取决于Foo(Foo在Foo $的extends子句中作为限定符出现) Intf)

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)

对于传递性,我们认为Foo依赖于它自身;因此,代码应该被编译时错误拒绝。

For transitivity, we have that Foo depends on itself; as such the code should be rejected with a compile-time error.

Bug 8041994


退一步,直接-JLS2中引入了类和接口的相关关系,以阐明JLS1并涵盖嵌套类的超类/超接口(例如描述中的AB)。

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).

错误6660289


此问题是由于javac执行类型变量边界属性wrt类属性的顺序。

This problem is due to the order in which javac perform attribution of type-variable bounds wrt class attribution.

1)类外部的归属< T extends Outer.Inner>

1a)外部归因触发外部类型变量的归属
2)Outer.T的归因。
2a)Outer.T的归因触发其声明的界限的归属

3)类Outer.Inner的归属< S扩展T>

3a)Outer.Inner的归因触发Outer.Inner的类型变量的归属

4)Outer.Inner的归属< S>

4a)Outer.Inner.S的归因触发了其声明的界限的归属

5)Outer.T的归因 - 这只会返回T的类型;正如您所看到的,在此阶段尚未在表示T类型的对象上设置T的绑定。

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.

稍后,对于每个属性类型变量, javac执行检查以确保给定类型变量的边界不会引入循环继承。但我们已经看到Outer.T没有设定界限;因为这是javac在尝试检测由Outer.Inner.S的声明边界引起的继承树中的循环时与NPE崩溃的原因。

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.

错误6663588


类型变量边界可能引用属于循环继承树的类,这会导致解析过程在查找符号时进入循环。

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中引入的解决方案是简单地禁止由限定符类型引入的循环以及实际的超类型。

To your specific question of "what is the problematic dependency?" it appears to be a complex compile-time symbol resolution edge case, and the solution introduced in JLS2 was to simply ban cycles introduced by qualifier types as well as actual supertypes.

换句话说,这理论上可以使用适当的改进来实现编译器,但是直到有人出现并实现这一点,才能禁止这种异常语言规范中的关系。

In other words this could theoretically be made to work with appropriate improvements to the compiler, but until someone comes along and makes that happen it's more practical to just ban this unusual relationship in the language specification.

这篇关于为什么类不能扩展其中出现的静态嵌套类?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆