文章目錄
- 127. Java 泛型 - 泛型類與子類型
- 1. 泛型類和接口的子類型化
- 示例:`ArrayList` 和 `List`
- 2. 自定義泛型接口的子類型化
- 示例:泛型接口的子類型
- 解釋
- 3. 泛型類和接口的類型參數
- 4. 總結
127. Java 泛型 - 泛型類與子類型
1. 泛型類和接口的子類型化
在 Java 中,可以通過擴展或實現泛型類或接口來對其進行子類型化。這意味著,如果一個類或接口是泛型的,它的類型參數將影響該類或接口的子類型關系。這個關系通過 extends
和 implements
子句來決定。
示例:ArrayList
和 List
考慮 Java 的 Collections
類庫,ArrayList<E>
實現了 List<E>
,而 List<E>
又擴展了 Collection<E>
。因此,ArrayList<String>
是 List<String>
的子類型,而 List<String>
又是 Collection<String>
的子類型。這是泛型類之間子類型關系的一種體現。
List<String> list = new ArrayList<>(); // OK, ArrayList<String> 是 List<String> 的子類型
這就表明,當不改變類型參數時,泛型類之間會保持子類型關系。ArrayList<String>
是 List<String>
的子類型,而 List<String>
又是 Collection<String>
的子類型。
2. 自定義泛型接口的子類型化
假設我們需要定義一個自定義的泛型接口 PayloadList
,它將泛型類型 P
的值與每個元素相關聯。例如,這個接口可能聲明如下:
interface PayloadList<E, P> extends List<E> {void setPayload(int index, P val);// 其他方法
}
在這個接口中,E
代表列表元素的類型,P
代表與每個元素相關聯的“有效負載”類型。
示例:泛型接口的子類型
接下來,我們可以創建 PayloadList
的具體類型參數化版本:
PayloadList<String, String> stringPayloadList = new SomePayloadListImpl<>();
PayloadList<String, Integer> integerPayloadList = new SomePayloadListImpl<>();
PayloadList<String, Exception> exceptionPayloadList = new SomePayloadListImpl<>();
PayloadList<String, String>
是List<String>
的子類型。PayloadList<String, Integer>
是List<String>
的子類型,盡管它使用了不同的泛型類型參數。PayloadList<String, Exception>
也是List<String>
的子類型,盡管它的第二個類型參數是Exception
。
解釋
這里的核心概念是:只要不改變類型參數之間的相對關系,泛型類型之間就能保留子類型關系。即使我們在泛型接口 PayloadList
中使用不同的類型參數,它們依然可以和 List<String>
保持子類型關系。關鍵是,類型參數 E
的一致性確保了我們可以將 PayloadList<E, P>
類型的對象賦值給 List<E>
類型的變量。
3. 泛型類和接口的類型參數
泛型類和接口的類型參數與它們的子類型關系密切相關。類型參數不僅決定了接口或類的功能,還影響了它們的繼承關系和泛型約束。例如,不能將 PayloadList<String, String>
直接賦值給 PayloadList<Integer, Integer>
,即使這兩個類型都繼承自 List<String>
,因為它們的第二個類型參數不同。
PayloadList<String, String> list1 = new SomePayloadListImpl<>();
PayloadList<Integer, Integer> list2 = new SomePayloadListImpl<>();// 這將會報錯,因為 list1 和 list2 不是相同類型,即使它們都繼承自 List<String>。
list1 = list2; // 編譯錯誤,類型參數不同
4. 總結
- 泛型類和接口的子類型化:泛型類或接口的子類型關系由類型參數確定。只要不改變類型參數之間的關系,子類型關系就能保留。例如,
ArrayList<String>
是List<String>
的子類型,而List<String>
又是Collection<String>
的子類型。 - 自定義泛型接口:我們可以定義自己的泛型接口,如
PayloadList
,并通過不同的類型參數創建不同的子類型。這些子類型之間仍然保持繼承關系。 - 類型參數的關系:泛型類或接口的類型參數決定了它們的繼承關系和可賦值性。類型參數不匹配的泛型類型不能互相賦值。
通過理解這一點,學員可以更好地理解泛型類和接口之間的繼承關系,以及如何自定義泛型接口和確保類型安全。