Java 泛型中? super T和? extends T的區別
經常發現有List<? super T>、Set<? extends T>的宣告,是什麼意思呢?<? super T>表示包括T在內的任何T的父類,<? extends T>表示包括T在內的任何T的子類,下面我們詳細分析一下兩種萬用字元具體的區別。
extends
List<? extends Number> foo3的萬用字元宣告,意味著以下的賦值是合法的:
// Number "extends" Number (in this context) List<? extends Number> foo3 = new ArrayList<? extends Number>(); // Integer extends Number List<? extends Number> foo3 = new ArrayList<? extends Integer>(); // Double extends Number List<? extends Number> foo3 = new ArrayList<? extends Double>();
- 讀取操作通過以上給定的賦值語句,你一定能從foo3列表中讀取到的元素的型別是什麼呢?你可以讀取到Number,因為以上的列表要麼包含Number元素,要麼包含Number的類元素。你不能保證讀取到Integer,因為foo3可能指向的是List<Double>。你不能保證讀取到Double,因為foo3可能指向的是List<Integer>。
- 寫入操作過以上給定的賦值語句,你能把一個什麼型別的元素合法地插入到foo3中呢?你不能插入一個Integer元素,因為foo3可能指向List<Double>。你不能插入一個Double元素,因為foo3可能指向List<Integer>。你不能插入一個Number元素,因為foo3可能指向List<Integer>。你不能往List<? extends T>中插入任何型別的物件,因為你不能保證列表實際指向的型別是什麼,你並不能保證列表中實際儲存什麼型別的物件。唯一可以保證的是,你可以從中讀取到T或者T的子類。
super
現在考慮一下List<? super T>。
List<? super Integer> foo3的萬用字元宣告,意味著以下賦值是合法的:
// Integer is a "superclass" of Integer (in this context) List<? super Integer> foo3 = new ArrayList<Integer>(); // Number is a superclass of Integer List<? super Integer> foo3 = new ArrayList<Number>(); // Object is a superclass of Integer List<? super Integer> foo3 = new ArrayList<Object>();
- 讀取操作通過以上給定的賦值語句,你一定能從foo3列表中讀取到的元素的型別是什麼呢?你不能保證讀取到Integer,因為foo3可能指向List<Number>或者List<Object>。你不能保證讀取到Number,因為foo3可能指向List<Object>。唯一可以保證的是,你可以讀取到Object或者Object子類的物件(你並不知道具體的子類是什麼)。
- 寫入操作通過以上給定的賦值語句,你能把一個什麼型別的元素合法地插入到foo3中呢?你可以插入Integer物件,因為上述宣告的列表都支援Integer。你可以插入Integer的子類的物件,因為Integer的子類同時也是Integer,原因同上。你不能插入Double物件,因為foo3可能指向ArrayList<Integer>。你不能插入Number物件,因為foo3可能指向ArrayList<Integer>。你不能插入Object物件,因為foo3可能指向ArrayList<Integer>。
PECS
請記住PECS原則:生產者(Producer)使用extends,消費者(Consumer)使用super。
生產者使用extends
如果你需要一個列表提供T型別的元素(即你想從列表中讀取T型別的元素),你需要把這個列表宣告成<? extends T>,比如List<? extends Integer>,因此你不能往該列表中新增任何元素。
消費者使用super
如果需要一個列表使用T型別的元素(即你想把T型別的元素加入到列表中),你需要把這個列表宣告成<? super T>,比如List<? super Integer>,因此你不能保證從中讀取到的元素的型別。
即是生產者,也是消費者
如果一個列表即要生產,又要消費,你不能使用泛型萬用字元宣告列表,比如List<Integer>。
例子
請參考java.util.Collections裡的copy方法(JDK1.7):
我們可以從Java開發團隊的程式碼中獲得到一些啟發,copy方法中使用到了PECS原則,實現了對引數的保護。
相關文章
- java泛型中<?>和<T>有什麼區別?Java泛型
- Java泛型T與?的區別Java泛型
- Java泛型中<?> 和 <? extends Object>的異同分析Java泛型Object
- T和?的區別
- Rust中,*const T和*mut T的區別是什麼?Rust
- Java 泛型 T,E,K,V,?,傻傻分不清?Java泛型
- C++中L和_T()之區別C++
- 科大訊飛t20pro和t10區別
- Dell T40和Dell T140有啥區別?
- c#中的ReadOnlySequence<T>和ReadOnlySequenceSegment<T>C#
- rust trait 關聯型別和泛型的區別RustAI型別泛型
- Java中建立泛型型別的例項Java泛型型別
- Rust中的智慧指標:Box<T> Rc<T> Arc<T> Cell<T> RefCell<T> Weak<T>Rust指標
- React.createClass和extends Component的區別React
- 再理解es6 中的 class super extends
- Java中的泛型Java泛型
- size_t 資料型別的好處資料型別
- Java™ 教程(泛型原始型別)Java泛型型別
- Java中基於泛型的交叉型別 - {4Comprehension}Java泛型型別
- 魅藍6與魅藍6T區別對比 魅藍6T和魅藍6有什麼區別?
- Java中的泛型方法Java泛型
- Java泛型型別擦除問題Java泛型型別
- TypeScript 基本型別和泛型的使用TypeScript型別泛型
- c#中Array,ArrayList 與List<T>的區別、共性與轉換C#
- golang,interface轉換型別 cannot convert t (typGolang型別
- 一加6和一加5T區別對比 一加6和一加5T哪個好?
- 深入解析Java中的泛型Java泛型
- Java中基本資料型別和包裝型別有什麼區別?Java資料型別
- TS中特殊型別-any、unknown、never和extends繼承約束、keyof的使用型別繼承
- java 中equals和==的區別Java
- Java 中 this 和 super 的用法詳解Java
- 基礎篇:深入解析JAVA泛型和Type型別體系Java泛型型別
- 【java】【泛型】泛型geneticJava泛型
- this和super的區別和應用 學習筆記筆記
- Kotlin 泛型中的 in 和 outKotlin泛型
- Java 泛型中的萬用字元Java泛型字元
- Java 中的泛型方法及 FunctionJava泛型Function
- Java 泛型中易混淆的地方Java泛型
- Java中的泛型程式設計:深入理解型別引數與型別邊界的使用Java泛型程式設計型別