泛型、陣列列表與協變

Sherioc發表於2024-08-18
public class Test {
    public static void main(String[] args) {
        ArrayList<XiaoMi> xiaoMiList = new ArrayList<XiaoMi>();

        ArrayList<BYD> bydList = new ArrayList<BYD>();

        run(xiaoMiList); //錯誤使用
    }
    
    public static void run(ArrayList<Car> list) {
        // 汽車跑的邏輯
        System.out.println("the car runs fast");
    }

}

疑問:xiaoMiList中的每個元素都是Car的子類,為什麼不能使用多型的方式實現將ArrayList傳給ArrayList

java中的協變

在Java中,協變是指一個型別的子型別可以被當作其父型別來使用。例如,如果 XiaoMi 是 Car 的子類,那麼 XiaoMi 的物件可以被當作 Car 的物件來使用。這是Java語言設計中的一項重要特性,它支援物件導向程式設計中的多型性。

陣列列表與協變

然而,儘管Java中的基本型別和引用型別支援協變,ArrayList 卻不支援協變。這是因為 ArrayList 的設計考慮到了型別安全性和避免潛在的執行時錯誤。

設計思想

Java中泛型擦除

1. 型別安全性:


Java的設計目標之一是保證型別安全性。如果 ArrayList<XiaoMi> 能夠被當作 ArrayList<Car> 使用,那麼可能會發生以下情況: 
* 可能意外地向 ArrayList<XiaoMi> 中新增了一個 BYD 物件,因為 BYD 也是 Car 的子類。
* 這種操作在編譯時是合法的,但在執行時會導致 ClassCastException,因為 ArrayList<XiaoMi> 實際上只能儲存 XiaoMi 物件。

2. 泛型擦除:


Java中的泛型是基於型別擦除實現的。這意味著在編譯時型別引數被替換為其實現的原始型別(例如 ArrayList<XiaoMi> 在執行時實際上就是 ArrayList<Object>),而在執行時型別引數的資訊被丟棄。
如果 ArrayList<XiaoMi> 能夠被當作 ArrayList<Car> 使用,那麼編譯器無法保證型別安全,因為它不知道 XiaoMi 是否是 Car 的子類。

相關文章