[英]java generic class & wildcards
我有一個Box泛型類,具有以下功能:
put
方法中的一個應允許客戶端插入一個框並將其內容添加到當前框中。 我希望這種方法能夠獲得兩種類型的盒子: Box<Number>
和Box<Integer>
,這就是我將put(Box<T>)
方法改為put(Box<? extends Number> box)
。 但是我收到了編譯警告。 我在這做錯了什么?
這是我當前的代碼:我得到的警告是:類型安全:未捕獲來自捕獲#1的投射? 將Number擴展為T.
public class Box<T> {
public T get() {
return element;
}
public void put(T element) {
this.element = element;
}
public void put(Box<? extends Number> box) {
put((T) box.get()); // this is where i get the warning
}
private T element;
}
public class BoxClient {
public static void main(String[] args) {
Box<Number> nBox = new Box<Number>();
Box<Integer> iBox = new Box<Integer>();
nBox.put(iBox);
}
}
改為
public void put(Box<? extends T> box) {
put(box.get());
}
如果我測試你的代碼,那么我會在這個方法中收到警告:
public void put(Box<? extends Number> box) {
put( (T) box.get());
}
警告是:
未經檢查的強制轉換:
java.lang.Number
到T
問題是您的泛型類型T
沒有邊界 ,因此它可以是任何東西,並且由於類型擦除它將被擦除為Object
。
變量box
的泛型類型有一個邊界,很明顯,它總是某種Number
。
你的cast (T) box.get()
現在是“不安全的”,因為box.get()
返回Number
的子類型, T
可以是任何東西,比如String
。 因此編譯無法確定此強制轉換是否總是正常並且不會拋出ClassCastException
。 這就是他警告你不安全演員的原因。
你的Box有一個泛型類型T
,它不對它的類型做任何假設(沒有界限)。 如果你的機器應該只能夠包含Number
S(和子類型的Number
),你可以把它改成: class Box<T extends Number>
。 和你的方法: put(Box<? extends T> box)
,以便它接受T
及其任何子類型。
您的類Box
定義了泛型類型T
T
可以是任何東西。 即“包含任何物體的盒子”
然后,你的方法收到一個Box<? extends Number>
Box<? extends Number>
。 即“包含數字類型的盒子”。
問題出在你的方法中:
public void put(Box<? extends Number> box) {
put(box.get());
}
該方法接收“包含數字的盒子”,然而,它對T
。 請記住, T
可以是任何東西,因此您可以執行強制轉換為實際上不是數字的東西。 考慮這個例子:
public class BoxClient {
public static void main(String[] args) {
Box<String> sBox = new Box<String>();
Box<Integer> iBox = new Box<Integer>();
iBox.put(1);
sBox.put(iBox);
System.out.println(sBox.get());
}
}
在這里,我創建了一個Box<String>
或“包含字符串的Box<Integer>
”並添加了一個Box<Integer>
或“一個包含一個數字的盒子”。 通過泛型代碼,這是有效的,因為T
可以是任何東西,但是,如果您嘗試執行它
java.lang.ClassCastException:java.lang.Integer無法強制轉換為java.lang.String
那是因為Integer
1不能轉換為String
。
為了確保永遠不會發生這種情況,您需要更改Box
的聲明以強制T extends Number
,如下所示:
public class Box<T extends Number> {
public T get() {
return element;
}
public void put(T element) {
this.element = element;
}
public void put(Box<? extends T> box) {
put((T) box.get());
}
private T element;
}
更新:如上所述,我之前的回答可能仍然不安全。 比方說,如果你有一個Box<Number>
並嘗試添加一個Box<Integer>
,它仍然會被允許並仍然拋出異常。
最好的解決方案是添加bayou.io的建議。 這樣你就可以確保:1:你的Box總是包含數字2:你的Box只能從其他擴展為T
Box中添加
更新2:如下面在newacct的評論中所述,對T
的演員也沒有必要。
希望這可以幫助!
您的問題導致事實,即Java 5中引入了泛型類型。因此,方法簽名不包含有關泛型類的信息。
課程草案:
public abstract class Draft<T> {
public abstract void put(T element);
public abstract void putDraft(Draft draft);
}
使用此草案,代碼保持可讀性,並且您沒有任何編譯器警告。
在這里查找有關此問題的更多信息。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.