接口的循环继承

时间:2016-02-08 12:53:17

标签: java inheritance interface cyclic

我理解为什么Java中不允许循环继承类,但我不明白为什么不允许循环继承。举例说明:

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

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

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

顺便说一下,我读了这个问题,但这不是关于接口而是类: Cyclic inheritance hierarchy in Java

提前致谢。

3 个答案:

答案 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 BB 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