2013-05-07 28 views
1

當試圖專門實現一個通用接口的類時遇到了問題,我想從超類繼承同一接口,但使用更具體的類型參數。以下片段顯示了一個不能編譯的合成但完整的示例。該註釋包含來自Java編譯器的錯誤消息。在尊重變化的同時多次繼承通用接口

interface Producer<T> { 
    T get(); 
} 

class NumberProducer implements Producer<Number> { 
    @Override 
    public Number get() { return null; } 
} 

// Producer cannot be inherited with different arguments: <java.lang.Integer> and <java.lang.Number> 
class IntegerProducer extends NumberProducer implements Producer<Integer> { 
    @Override 
    public Integer get() { return null; } 
} 

PECS意義,Producer<T>製片,所以Producer<Integer>Producer<Number>一個亞型,但也沒有辦法,宣佈在Producer<T>定義。 Java不允許IntegerProducerNumberProducerProducer<Integer>繼承,同時IntegerProducer將同時繼承Producer<Integer>Producer<Number>

有沒有一個標準的方法來解決這個限制,例如,不需要這種繼承就可以解決相同問題的模式?

+0

你爲什麼要實施IntegerProducer接口?你也可以在不實現接口的情況下覆蓋get()方法。 – 2013-05-07 11:17:27

+0

你能提供一個如何使用這些類的例子嗎?我不確定即使是製作'NumberProducer'通用的常見建議也會做你想做的事情。如果你使用'NumberProducer 實現Producer ',你不能返回NumberProducer.get()中'null'以外的任何東西,因爲你不知道'Number'的哪個子類型是'T'。也就是說,你不能返回新的Number()(我知道構造函數不存在,但忍受着我),因爲'T'實際上可能是'Integer'。 – millimoose 2013-05-07 11:37:25

回答

2

只是一個參數添加到超類:

interface Producer<T> { 
    T get(); 
} 

class NumberProducer<T extends Number> implements Producer<T> { 
    @Override 
    public T get() { return null; } 
} 

class IntegerProducer extends NumberProducer<Integer> { // Implicit: implements Producer<Integer> 
    @Override 
    public Integer get() { return null; } 
} 
+0

這就是我現在所做的,謝謝。我引入了一個'SpecializableNumberProducer ',並從中繼承了'NumberProducer',但不添加任何實現,而是爲類型參數傳遞'Number'。通過這種方式,NumberProducer的用戶不必在每次使用時顯式傳遞'Number'作爲類型參數。 Ben Schulz的回答更詳細地介紹了泛型的實現以及阻止我的原始代碼運行的原因。 – Feuermurmel 2013-05-07 13:48:49

0

如果你想確保T是一個亞型特異性的,你可以使用

interface Producer<T extends Number> 

不知道製作人雷爾是什麼,所以我必須猜測。

更新: 如果我理解你是正確的,那麼我會說,你需要聲明一個生產者的接口。這很簡單。

從這個接口我會派生一個新的接口與respecitve基類型。

即:

interface Producer 
{ 
    base functions 
}; 


interface Newproducer<T extends Producer> 
{ 
}; 

這是你腦子裏有什麼?

+0

問題是我想使用'Producer'接口來處理與'Number'不兼容的類型,例如'String'。所以我不能在那裏綁定類型參數。 – Feuermurmel 2013-05-07 11:41:30

+0

更新了我的方法。不知道這是你的想法。這聽起來有點像我的工廠,但不知道你打算怎麼說這很難說。 – Devolus 2013-05-07 11:50:17

1

假設我們有一個簡單的方法gimme

public static <T> T gimme(Producer<T> p) { return p.get(); } 

gimme什麼情況下被知道關於T。它可能是Number,Integer或任何其他參考類型。所以,由於擦除,編譯器發出一個到Producer.get()Object的接口調用,而不是對IntegerProducer.get()Integer的特定調用。實施Producer<T>T != Object的所有類型也暗含執行Producer.get()Object。這個隱含的實現轉向具體的實現。這可能是NumberProducer.get()NumberIntegerProducer.get()Integer,但不是兩個都是。這就是爲什麼你不能兩次實現相同的接口。

其他語言允許通過定義網站差異,其中Producer<Integer>Producer<Number>的子類型,但唉,Java沒有。常見的解決方法是使NumberProducer也是通用的。

+0

我明白你的代碼片段中的調用'p.get()'將被編譯爲一個調用'Producer.get()Object'的函數,它將由'NumberProducer'實現,但'IntegerProducer'可以覆蓋該方法並且讓它調用'NumberProducer.get()Integer',所以我在那裏看不到問題。 – Feuermurmel 2013-05-07 13:34:16

+0

@Feuermurmel具有聲明網站差異的語言是可能的; 'IntegerProducer.get()'會覆蓋'NumberProducer.get()'。然而,在Java中,它們將是重載方法,編譯器只能轉發到其中的一個。因此它是不允許的。 – 2013-05-07 17:22:25