为什么Java禁止继承内部接口?

为什么Java禁止继承内部接口?,java,inheritance,dependencies,cyclic,Java,Inheritance,Dependencies,Cyclic,也就是说,为什么以下“循环依赖性”不可能 public class Something implements Behavior { public interface Behavior { // ... } } 因为接口不引用外部类,所以应该允许这样做;然而,编译器迫使我在类之外定义这些接口。对这种行为有什么合乎逻辑的解释吗?假设您就是编译器 我们是说你要创建一个类。 这个类实现了行为。。。 但是行为还不存在,因为有些东西还没有注册 你明白这个问题吗 将类视为包含

也就是说,为什么以下“循环依赖性”不可能

public class Something implements Behavior {
    public interface Behavior {
        // ...
    }
}

因为接口不引用外部类,所以应该允许这样做;然而,编译器迫使我在类之外定义这些接口。对这种行为有什么合乎逻辑的解释吗?

假设您就是编译器

我们是说你要创建一个类。 这个类实现了行为。。。 但是行为还不存在,因为有些东西还没有注册

你明白这个问题吗


将类视为包含内容的框。行为是包含在盒子里的东西。但是有些东西并不存在。

语言规范禁止这一简单事实就足够了

我可以想到一些原因:

  • 那没用

  • 无论出于什么原因,你可能想使用这个,我相信有更好的选择

  • 子类应该扩展基类,那么为什么要在它自己的子类中声明基类呢

  • 让一个单独的类扩展您的内部类是违反直觉的


规范中的相关规则:

如果在C的extends或implements子句中提到T作为超类或超接口,或者作为超类或超接口名称的限定符,则类C直接依赖于类型T

如果在I的extends子句中提到T作为超级接口或超级接口名称中的限定符,则接口I直接依赖于类型T

因此,如果
A扩展了|实现了B.C
,则A依赖于
C
B
。然后规范禁止循环依赖

在依赖项中包含
B
的动机尚不清楚。正如您所提到的,如果将
B.C
提升到顶层
C2
,就类型系统而言,没有太大不同,那么为什么
A扩展C2
是可以的,而不是
A扩展B.C
?授予嵌套类型
B.C
确实对
B
的内容有一些访问权限,但我在规范中找不到任何使
a扩展B.C
麻烦的东西


唯一的问题是当
C
是一个内部类时。假设
B=A
A扩展A.C
应该被禁止,因为存在“封闭实例”的循环依赖关系。这可能是真正的动机——禁止外部类继承内部类。实际的规则更一般化,因为它们更简单,即使对于非内部类也有很好的意义。

听起来类加载器必须先阅读类才能知道它首先定义类所需的接口。。。我不知道类加载的细节,但这似乎很明显。@donneo:由于编译器抱怨“循环依赖”,我想它已经知道在内部类中定义了哪些类型。对我来说,这似乎是一个任意的限制。@PhilipK:你在用什么编译器?我的(Oracle JDK 6和7)只是抱怨他们“找不到符号”。除此之外:好问题,因为嵌套接口在技术上并不真正依赖外部类,所以这可能是合法的。@joachimsuer:我也在使用标准的Oracle JDK 6;但是,在上面的示例中,您需要实际编写
。。。实现一些东西。行为
-我的IDE自动包含必要的导入语句。当你这样做时,编译器应该用循环依赖错误来爆炸。这是一个有效的答案,如果问题是关于C++的。是的,但是行为是一个接口,因此不依赖于创建某个东西。是的,因为那个接口是某个东西的一部分。在引用行为之前,需要存在一些东西,但要创建一些东西,则需要引用行为。在您的情况下,您显然没有从某个地方导入“行为”。让我们假设您的类的某个东西在包“my.fancy.pack”中,那么某个东西的全名是“my.fancy.pack.Something”。因此,在您的“实现”部分,您基本上编写了:class my.fancy.pack.Something实现my.fancy.pack.behavior”。然而,您的接口是:“my.fancy.pack.Something.behavior”!因此正如Jeromy正确指出的那样,编译器无法通过“隐含”找到您的行为“name.@PhilipK我说的不是实例,而是类。内部接口位于其封闭类的命名空间中,因此为了能够引用它,封闭类需要已加载,而无法加载,因为它正在引用其封闭接口。这对于需要回调接口传递到其他类的情况非常有用。