2014-02-10 28 views
3

在我正在使用的一些代碼中,我有一個現有的第三方API實現了從A擴展的事物(也許不是直接的,而是通過X,也許還實現了一堆其他接口)。Java:是否有可能說變量類型必須滿足多重繼承/接口要求

現在爲我正在處理的代碼,我有一個接口IB,它提供了A提供的附加功能。因爲我的很多代碼實際上都要求傳遞給它的對象擴展了A,並且還實現了IB,但是沒有辦法爲我的成員變量聲明我能想到的。但選擇A或IB會導致很多演員陣容。

我猜如果A有/有一個接口IA會解決這個問題,但是我沒有辦法改變A,或者我的IB實現不需要擴展A(第三方代碼使用A,並且需要通過它來關心很多管理,持久性,網絡,用戶接口等)。

class Z { 
    private List<?what here?> items; 
    /**The implementer of IB should know how to find the Z instance and call this.*/ 
    private void subscribe(? item) { 
     items.add(item); 
    } 
    public void doSomethingWithItems() { 
     ...code thats requires facilities from A and IB... 
    } 

回答

2

使用通用助手類,其類型參數使您可以使用一個類型路口:

class Z { 

    private static final class Wrapper<T extends A & IB> { 

     private final T item; 

     Wrapper(final T item) { 
      this.item = item; 
     } 

     void doWork() { 
      // code thats requires facilities from A and IB 
     } 
    } 

    private List<Wrapper<?>> wrappers; 

    private <T extends A & IB> void subscribe(T item) { 
     wrappers.add(new Wrapper<T>(item)); 
    } 
    public void doSomethingWithItems() { 
     for (final Wrapper<?> wrapper : wrappers) { 
      wrapper.doWork(); 
     } 
    } 

我介紹了這個帖子了類似的回答:Java generics type mismatch in method signature

+0

「列表>」正在「列表>」我認爲?去嘗試這個,並沒有真正考慮使這個方法是通用的。 –

+0

@FireLancer是的,糾正。我回過頭來看看它的名字:) –

+1

這是一個非常簡潔的技巧,可以從Java提供的類型參數的交集類型中引導第一類交集類型。我將添加到我的工具箱醜陋的泛型問題:-) – meriton

3

您可以指定一個類型路口

<T extends A & IB> 

的規則,如果類型之一是一類,它必須首先列出。

如果可以的話我會鍵入類:

class Z<T extends A & IB> { 
    private List<T> items; 

    private void subscribe(T item) { 
     items.add(item); 
    } 
    public void doSomethingWithItems() { 
     // the items are both A and IB 
    } 
} 

如果您不能鍵入Z,去類型的方法:

class Z { 
    private List<A>items; 

    private <T extends A & IB> void subscribe(T item) { 
     items.add(item); 
    } 
    public void doSomethingWithItems() { 
     // items are A, but if you want IB functionality you must cast. 
     // the cast is safe if items are only added via subscribe() 
    } 
} 
+1

T是什麼類型? Z實例用於滿足要求的任何事物,而不是特定類型的事物,因此同一個z實例可以被賦予Abc或Xyz對象,除了擴展A和實現IB之外,它們是不相關的。 –

+0

http://docs.oracle.com/javase/specs/jls/se7/html/jls-4.html#jls-4。9「不能直接將交集類型作爲程序的一部分來編寫,沒有語法支持這一點。」我想這是什麼? –

+0

@fire huh?這編譯。有什麼問題? – Bohemian

1

你可以做一個新的抽象類,這兩個用抽象方法實現IB,並擴展A.然後,可以讓所有需要使用的類擴展新的抽象類。

+0

IC做什麼?一個抽象類就沒有問題,只要在整個系統中沒有其他任何東西,任何形式的重疊都會這樣做。 –

+0

對不起,我不瞭解您的評論。你是否建議有兩個不同的接口'IB'和'IC',我需要一些擴展'A'並實現'IB'的類。一些擴展'A'並實現'IC'的類;並且還擴展'A'並實現'IB'和'IC'?這是你的問題,還是我誤解了你? –

+0

是的,潛在的,它在沒有多重繼承問題。 AExtended表示,IB的某些實現可能已經有了不同的基礎。 IB是一個以 –

2

這將是最ideomatic如果IB是一個IA的子類型,但是如果你不能這樣做...

由於Java不支持頭等交集類型,所以很難在代碼中表達它。也就是說,Java只支持類型參數邊界中的交集類型,並且我們不能在字段聲明中使用類型參數,而不要求列表中的所有元素都是IB的相同子類型。

因此,我能想到的最好的近似值是強制約束只能在公共API,並且使用內部轉換:

class Z { 
    private List<A> items; 

    private <B extends A & IB> void subscribe(B item) { 
     items.add(item); 
    } 

    public void doSomethingWithItems() { 
     for (A a : items) { 
      IB b = (IB) a; // safe because we checked it on subscription 
      // use features of A and IB 
     } 
    } 
} 

是的,這是醜陋的。這就是爲什麼像Ceylon這樣的新型JVM語言具有第一類交叉類型的原因。也就是說,在錫蘭,人們可以簡單地寫:

class Z() { 

    List<A & IB> items; 

    void subscribe(A & IB item) { 
     items.add(item); 
    } 

    void doSomethingWithItems() { 
     for (item in items) { 
      // use features of A and IB 
     } 
    } 
} 
相關問題