2016-02-08 63 views
0

我明白了爲什麼類的循環繼承Java不允許,但我不明白爲什麼的接口循環繼承是不允許的。舉例說明:循環繼承接口

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 BB extends A?誰會贏?什麼new C().getX()將打印?還是應該是新類型的編譯錯誤?

一般來說,這樣的功能似乎會帶來更多的問題,而不是產生效益。

1

見Java語言規範9.1.3 Superinterfaces and Subinterfaces

接口I 上的參考類型T如果下列任何適用取決於

  • 我直接依賴於T.

  • 我直接依賴於依賴於T的類C(§8.1.5)。

  • 我直接依賴於依賴於T的接口J(遞歸地使用此定義)。

如果接口依賴於自身,則會出現編譯時錯誤。

如果在運行時檢測到循環聲明的接口,因爲接口已加載,則引發ClassCircularityError§12.2.1)。

至於爲什麼,我喜歡Andy Turner's comment

如果Foo extends Bar,那麼Foo每個實例也Bar。如果Bar extends Foo,那麼Bar的每個實例也是Foo。如果兩者都被允許是正確的,那麼這兩個條件可以滿足的唯一方式是如果Foo == Bar