为啥Java禁止继承内部接口?
Posted
技术标签:
【中文标题】为啥Java禁止继承内部接口?【英文标题】:Why is Java prohibiting inheritance of inner interfaces?为什么Java禁止继承内部接口? 【发布时间】:2011-12-21 01:39:24 【问题描述】:即为什么下面的“循环依赖”是不可能的?
public class Something implements Behavior
public interface Behavior
// ...
由于接口不引用外部类,这应该是允许的;但是,编译器迫使我在类之外定义这些接口。这种行为有什么合乎逻辑的解释吗?
【问题讨论】:
听起来类加载器必须先读取类才能知道它首先需要定义类的接口......我不知道类加载的细节,但似乎很明显。 @donneo:由于编译器抱怨“循环依赖”,我想它已经知道内部类中定义了哪些类型。这对我来说似乎是一个任意的限制。 @PhilipK:你用的是什么编译器?我的(Oracle JDK 6 和 7)只抱怨他们“找不到符号”。除此之外:好问题,因为嵌套接口在任何技术上都不真正依赖外部类,这可能是合法的。 @JoachimSauer:我也在使用标准的 Oracle JDK 6;但是,在上面的示例中,您需要实际编写... implements Something.Behavior
- 我的 IDE 自动包含必要的导入语句。当你这样做时,编译器应该会出现循环依赖错误。
【参考方案1】:
spec中的相关规则:
http://java.sun.com/docs/books/jls/third_edition/html/classes.html#8.1.4
如果在 C 的扩展或实现子句中提到 T 作为超类或超接口,或者作为超类或超接口名称的限定符,则 C 类直接依赖于类型 T。
http://java.sun.com/docs/books/jls/third_edition/html/interfaces.html#9.1.3
如果在 I 的扩展子句中提到 T 作为超接口或作为超接口名称中的限定符,则接口 I 直接依赖于类型 T。
因此,如果A extends|implements B.C
,A 取决于C
和B
。然后,规范禁止循环依赖。
在依赖项中包含B
的动机尚不清楚。正如您所提到的,如果将B.C
提升为***C2
,就类型系统而言并没有太大的不同,那么为什么A extends C2
可以,但A extends B.C
不行?授予嵌套类型 B.C
确实可以访问 B
的内容,但我在规范中找不到任何使 A extends B.C
麻烦的东西。
唯一的问题是C
是一个内部类。假设B=A
,A extends A.C
应该被禁止,因为存在“封闭实例”的循环依赖。这可能是真正的动机——禁止外部类继承内部类。实际的规则更通用,因为它们更简单,而且即使对于非内部类也很有意义。
【讨论】:
【参考方案2】:语言规范禁止这样做的简单事实就足够了。
我能想到的一些原因:
不会有用的。
无论出于何种原因,您可能想要使用它,我确信存在更好的选择。
子类应该扩展基类,那么为什么要在自己的子类中声明基类?
让一个单独的类扩展你的内部类是违反直觉的。
【讨论】:
这对于我们需要回调接口传递给不同类的情况很有用。【参考方案3】:想象你是编译器。
我们说你要创建一个类Something。 此类实现行为... 但是 Behavior 还不存在,因为Something 尚未注册...
你明白这个问题吗?
将类视为包含事物的盒子。行为包含在“Something”框中。但是Something不存在。
【讨论】:
如果问题是关于 C++ 的,这将是一个有效的答案。 是的,但是 Behavior 是一个接口,因此不依赖于 Something 的创建。 是的,因为该接口是Something的一部分。有些东西需要存在才能引用行为,但要创建东西你需要引用行为。 在您的情况下,您显然没有从某个地方导入“行为”。让我们假设您的类 Something 在包“my.fancy.pack”中,那么 Somthing 的全名是“my.fancy.pack.Something”。所以,在你的“实现”部分你基本上写:class my.fancy.pack.Something implements my.fancy.pack.Behaviour”。但是你的界面是:“my.fancy.pack.Something.Behaviour”!因此作为Jeromy正确指出编译器无法使用“隐含”名称找到您的行为。 @PhilipK 我不是在谈论实例:我在谈论类。内部接口在其封闭类的命名空间中,因此要能够引用它,封闭类需要已经加载,并且由于引用了它的封闭接口而无法加载。以上是关于为啥Java禁止继承内部接口?的主要内容,如果未能解决你的问题,请参考以下文章