2012-09-09 35 views
2

我有一些內部使用泛型的代碼。到目前爲止,一切都很好,直到通過公共API公開功能。問題與以下玩具示例相同:我有一個List包裝物品,其中包含特定的子類型(本例中爲T extends Number)。當我想返回List時,我正在返回一個List<Wrapper<? extends Number>>,這使得客戶端代碼非常冗長。擺脫返回值中的通配符參數

是否有可能將退貨類型更改爲List<Wrapper<Number>>?客戶不需要知道,Wrappers包含任何特定類型的數字。我嘗試了幾種鑄造方法,但它們都會因編譯錯誤而失敗。

public static List<Wrapper<? extends Number>> getNumbers() { 
    Wrapper<Integer> number1 = new Wrapper<Integer>(1); 
    Wrapper<Double> number2 = new Wrapper<Double>(2.); 

    List<Wrapper<? extends Number>> numbers = new ArrayList<Wrapper<? extends Number>>(); 
    numbers.add(number1); 
    numbers.add(number2); 
    return numbers; 
} 

class Wrapper<T extends Number> { 
    private final T item; 
    Wrapper(T item) { 
     this.item = item; 
    } 
    T getItem() { 
     return item; 
    } 
} 

回答

0

據我所知,如果你想返回T.當你想返回牛逼

0

我剛剛發現下面的方法工作,就不能返回T的亞型是不可能的。任何有關潛在隱患的反饋和意見仍然非常感謝。

public static List<Wrapper<Number>> getNumbers() { 
    Wrapper<Integer> number1 = new Wrapper<Integer>(1); 
    Wrapper<Double> number2 = new Wrapper<Double>(2.); 
    List<Wrapper<? extends Number>> numbers = new ArrayList<Wrapper<? extends Number>>(); 
    numbers.add(number1); 
    numbers.add(number2); 
    return (List<Wrapper<Number>>)(List<?>)numbers; 
} 
+1

這是錯誤的。 '包裝'不是'包裝',即使'整數'是'數字'。所以你在做什麼是撒謊的類型系統。 – newacct

+0

另外,如果你打算這樣做,爲什麼不直接聲明'number1'和'number2'是'Wrapper '?那麼你不需要做任何瘋狂的投射。 – newacct

2

根據你表現出你的Wrapper類型,Wrapper<? extends Number>正是你想要什麼你的情況,因爲這是唯一可能獲得的物品出你Wrapper(它是一個製片人),和不可能放入物品。因此,當您致電getItem()Wrapper<? extends Number>時,它會返回Number,這正是您想要的。它不適合你的需求?

「詳細」是不是沒有扔掉類型安全的合法理由。

+0

在我的情況下,我不使用'Number',而是在我的庫中使用特定類型的子類型。通過API我不想公開事實,這些亞型存在,但'?延伸「正好表明這一點。保持代碼簡潔可讀絕對是一個目標,但我同意「生產者」方面。我知道這是「作弊」,但你能否看到實際的含義?另一種解決方案似乎是將'數字'中的所有項目「重新包裝」爲新創建的「包​​裝」,但這真的不同嗎? – qqilihq

+0

+1。 OP應該更改客戶端代碼......或者更好,避免這種泛型的濫用...... –

+0

@qqilihq:'?擴展X'表示「X」或其子類型。這並不一定意味着存在「X」的子類型。例如,你可以寫'?擴展字符串「,但不能有任何字符串的子類型。從泛型的角度來看,你應該使用'?因爲你的代碼中沒有任何內容依賴於類型參數。 – newacct