2016-02-08 4 views
0

Я понимаю, почему циклическое наследование классов не допускается на Java, но я не понял, почему циклическое наследование интерфейсов не допускается. Чтобы проиллюстрировать:Cyclic Inheritance of Interfaces

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

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

Интерфейсы не нуждаются в создании экземпляра, а затем, что мешает им расширять друг друга?

Кстати, я прочитал этот вопрос, но это не об интерфейсах, но классы: Cyclic inheritance hierarchy in Java

Спасибо заранее.

+15

Какой может быть хороший способ разрешить это? – Tunaki

+0

... Не могли бы вы просто объединить их полностью или иметь общую базу, если хотите? – EpicPandaForce

+0

Там могут быть очень редкие случаи, когда каждый интерфейс соответствует правилу «is-a», таким образом, может расширять друг друга. Это не так. Почему это не разрешено? Имеет ли это опасность для программ? Не потому, что я буду использовать его наверняка, а потому, что может быть что-то, чему я буду учиться на этом. – Haggra

ответ

2

Нет, но расширение интерфейса - это способ раскола соглашения. Помните, что интерфейс - это соглашение, обеспечивающее реализацию набора методов.

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

Возможно, теоретических трудностей нет, но это создаст ненужные осложнения. Несколько на имя:

  • В настоящее время обхода интерфейсов класса (с помощью рекурсивных вызовов 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()? Или это должен быть новый тип ошибки компиляции?

В целом кажется, что такая функция принесет больше проблем, чем приносит пользу.Спецификация

1

См языка Java 9.1.3 Superinterfaces and Subinterfaces:

Интерфейс I зависит от опорного типа Т, если любое из следующих условий:

  • Я напрямую зависит от Т.

  • Я напрямую зависит от класса C, который зависит от T (§8.1.5).

  • Я напрямую зависит от интерфейса J, который зависит от T (используя это определение рекурсивно).

Это ошибка времени компиляции, если интерфейс зависит от самого себя.

Если круговые объявленные интерфейсы обнаруживаются во время выполнения, когда загружаются интерфейсы, то бросается ClassCircularityError (§12.2.1).

А почему, мне нравится Andy Turner's comment:

Если Foo extends Bar, то каждый экземпляр Foo также Bar. Если Bar extends Foo, то каждый экземпляр Bar также является Foo. Если им было позволено быть истинным, то единственным способом, которым могут быть удовлетворены два условия, является Foo == Bar.

 Смежные вопросы

  • Нет связанных вопросов^_^