【泛型】泛型上下邊界

上一篇 【泛型】通配符與嵌套
通配符可以是任意類類型,在實際業務中使用通配符時,可能會遇到很多安全問題,如傳入的泛型類沒有特定的方法或屬性,類型轉換錯誤等。爲了防止這些問題的發生,就有了上下邊界,用於指定通配符的範圍。

1 泛型上限extends

上限extends指定的類型必須是繼承某個類,或者某個接口,即<=,如

? extends Fruit
T extends List

網絡圖片

// 容器類(裝食物用)
public class Container<T> {
    private T obj;

    public Container(){}

    public Container(T obj){
        this.obj = obj;
    }

    public T getObj() {
        return obj;
    }

    public void setObj(T obj) {
        this.obj = obj;
    }
}

示例類:

public class Food<T> {
    private T obj;
    public Food(T obj){
        this.obj = obj;
    }
    public T getObj() {
        return obj;
    }

    public void setObj(T obj) {
        this.obj = obj;
    }
}
public class Fruit<T> extends Food{
    public Fruit(T obj) {
        super(obj);
    }
}
public class Apple<T> extends Fruit{
    public Apple(T obj) {
        super(obj);
    }
}
public class Banana<T> extends Fruit{
    public Banana(T obj) {
        super(obj);
    }
}

public class Meat<T> extends Food{ 
    public Meat(T obj) {
        super(obj);
    }
}
public class Pork<T> extends Meat{
    public Pork(T obj) {
        super(obj);
    }
}

調用

// 主函數
public static void main(String[] strs) {
          // 水果盤
        Container<Fruit> fruits = new Container<Fruit>();
        // 香蕉籃
        Container<Banana> bananas = new Container<Banana>();
        // 菜盤
        Container<Pork> porks = new Container<Pork>();
        // 一個水果
        Fruit fruit = new Fruit("水果");
        // 一根香蕉
        Banana banana = new Banana("香蕉");
        // 一個蘋果
        Apple apple = new Apple("蘋果");
        // 一塊豬肉
        Pork pork = new Pork("土豬肉");
        Meat meat = new Meat("肉");

        // 把洗好的水果裝盤
        fruits.setObj(fruit);
        fruits.setObj(apple);
        bananas.setObj(banana);

        Container<? super Meat> container = new Container<>();
        container.setObj(pork);

        Container<? extends Meat> container1= new Container<>();
        //container1.setObj(meat);會報錯

        // 把炒好的土豬肉裝盤
        porks.setObj(pork);
}

2 泛型下限super

? super 指定類型

指定類型不能小於操作的類,即指定類型或指定類型的父類…父類的父類最終至Object,且不能爲任意父類的其他子類。
圖片來自網絡

// 加菜
public static void addDish(Container<? super Meat> container) {
    // 裝土豬肉
    container.setObj(new Pork("土豬肉"));
    // 裝牛肉
    container.setObj(new Pork("烤肥牛"));
}

// 主函數
public static void main(String[] strs) {
    // 菜盤 
    Container<Food> foods = new Container<Food>();
    // 專用裝肉盤 
    Container<Meat> meats = new Container<Meat>();
    // 水果籃
    Container<Fruit> fruits = new Container<Fruit>();
        
    // 我們喫飯的時候菜喫完,所以我們加菜
    // 廚師準備用盤子裝菜
        
    // 用菜盤裝菜
    addDish(foods);
    // 用專用裝肉盤裝菜
    addDish(meats);
    // 但不能用水果籃裝菜,一使用編譯器就會提示我們異常
//    addDish(fruits);
}

總結

這兩種方式基本上解決了之前所說的問題,但是同時,也有一定的限制。

1.上限<? extends T>不能往裏存,只能往外取 (即:只能get)

因爲編譯器只知道容器裏的是Fruit或者Fruit的子類,但不知道它具體是什麼類型,所以存的時候,無法判斷是否要存入的數據的類型與容器種的類型一致,所以會拒絕set操作。

2.下限<? super T>往外取只能賦值給Object變量,不影響往裏存

因爲編譯器只知道它是Fruit或者它的父類,這樣實際上是放鬆了類型限制,Fruit的父類一直到Object類型的對象都可以往裏存,但是取的時候,就只能當成Object對象使用了。

所以如果需要經常往外讀,則使用<? extends T>,如果需要經常往外取,則使用<? super T>。

參考:

  1. https://www.jianshu.com/p/0c318bb54502
  2. https://zhuanlan.zhihu.com/p/97517915
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章