我理解为什么Java中不允许循环继承类,但我不明白为什么不允许循环继承。举例说明:
interface Foo extends Bar {/*methods and constants*/}
interface Bar extends Foo {/*methods and constants*/}
接口不需要实例化,那么是什么阻止它们相互扩展?
顺便说一下,我读了这个问题,但这不是关于接口而是类: Cyclic inheritance hierarchy in Java
提前致谢。
答案 0 :(得分:3)
不,但扩展接口是分割协议的一种方式。请记住,接口是提供一组方法实现的协议。
public interface A extends B {
public void myMethod();
public void myOtherMethod();
}
您说接口A
是由这些方法和接口B
中的所有方法定义的。现在,如果接口B
说..
public interface B extends A {}
你说接口B
是由接口A
中的方法定义的。那么什么定义了接口A
。几个方法和接口B
。什么定义了接口B
?接口A
,由几个方法和接口B
定义!看看这是怎么回事?
允许这样做是没有道理意义的。
答案 1 :(得分:1)
可能没有理论上的困难,但这会造成不必要的复杂情况。一些名字:
目前遍历类接口(通过Class.getInterfaces()
的递归调用)可以保证产生有限的结果,可能是重复,但仍然如此。例如,此类代码有效:
private static void fillInterfaces(Class<?> clazz, Set<Class<?>> set) {
if(clazz == null) return;
for (Class<?> iclass : clazz.getInterfaces()) {
set.add(iclass);
fillInterfaces(iclass, set);
}
fillInterfaces(clazz.getSuperclass(), set);
}
public static Set<Class<?>> getAllInterfaces(Class<?> clazz) {
Set<Class<?>> result = new HashSet<>();
fillInterfaces(clazz, result);
return result;
}
类似的代码已经编写并在许多地方工作。通过提议提供循环接口,这将导致无限递归。
目前(在Java-8中)接口也可以为其父接口定义默认实现,必要时替换父实现。例如:
interface A {
default public String getX() {return "A";}
}
interface B extends A {
default public String getX() {return "B";}
}
static class C implements A, B {} // ok, C.getX() returns "B"
如果现在A extends B
,则A
获胜:
interface A extends B {
default public String getX() {return "A";}
}
interface B {
default public String getX() {return "B";}
}
static class C implements A, B {} // ok, C.getX() returns "A"
但是A extends B
和B extends A
会怎样?谁会赢? new C().getX()
会打印什么?或者它应该是新类型的编译错误?
总的来说,似乎这样的特征会带来更多的问题而不是产生好处。
答案 2 :(得分:1)
请参阅Java语言规范9.1.3 Superinterfaces and Subinterfaces:
如果满足以下任何条件,则依赖的接口在引用类型T上:
我直接依赖于T.
我直接依赖于依赖于T(§8.1.5)的C类。
我直接依赖于依赖于T的接口J(递归使用此定义)。
如果接口依赖于自身,则是编译时错误。
如果在运行时检测到循环声明的接口,则在加载接口时,会抛出
ClassCircularityError
(§12.2.1)。
至于为什么,我喜欢Andy Turner's comment:
如果
Foo extends Bar
,那么Foo
的每个实例也都是Bar
。如果Bar extends Foo
,那么Bar
的每个实例也都是Foo
。如果两者都被允许为真,则可以满足这两个条件的唯一方法是Foo == Bar
。