簡體   English   中英

java泛型類和通配符

[英]java generic class & wildcards

我有一個Box泛型類,具有以下功能:

  • 2個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.NumberT

問題是您的泛型類型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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM