0

我理解为什么 Java 中不允许类的循环继承,但我不明白为什么不允许接口的循环继承。为了显示:

interface Foo extends Bar {/*methods and constants*/}

interface Bar extends Foo {/*methods and constants*/}

接口不需要实例化,那么是什么阻止它们相互扩展呢?

顺便说一句,我读了这个问题,但这不是关于接口而是类: Java 中的循环继承层次结构

提前致谢。

4

3 回答 3

3

No, but extension of an interface is a way of splitting up the agreement. Remember, an interface is an agreement to provide an implementation of a set of methods.

public interface A extends B {
    public void myMethod();
    public void myOtherMethod();
}

You're saying interface A is defined by these methods and all the methods in interface B. Now if interface B says..

public interface B extends A {}

you're saying that interface B is defined by the methods in interface A. Well what defines interface A. A couple of methods and interface B. And what defines interface B? Interface A, which is defined by a couple of methods and interface B! See where this is going?

It makes no logical sense to allow this.

于 2016-02-08T13:00:45.273 回答
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"
    

    如果 now 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 BB extends A怎么办?谁会赢?new C().getX()会打印什么?还是应该是新型的编译错误?

一般来说,这样的特性似乎带来的问题多于产生的好处。

于 2016-02-11T08:22:08.073 回答
1

请参阅 Java 语言规范9.1.3 超接口和子接口

如果以下任何一项为真,则接口 I依赖于引用类型 T:

  • 我直接依赖于T。

  • 我直接依赖于依赖于 T 的 C 类(第 8.1.5 节)。

  • I 直接依赖于一个依赖于 T 的接口 J(递归地使用这个定义)。

如果接口依赖于自身,则为编译时错误。

如果在运行时检测到循环声明的接口,则在加载接口时,ClassCircularityError会抛出 a(第 12.2.1 节)。

至于为什么,我喜欢安迪·特纳的评论

如果Foo extends Bar,那么 的每个实例Foo也是一个Bar。如果Bar extends Foo,那么 的每个实例Bar也是一个Foo。如果两者都被允许为真,那么满足这两个条件的唯一方法就是 if Foo == Bar

于 2016-05-14T00:46:27.683 回答