您好,登錄后才能下訂單哦!
今天小編給大家分享一下Java泛型之協變、逆變、extends與super選擇方法的相關知識點,內容詳細,邏輯清晰,相信大部分人都還太了解這方面的知識,所以分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后有所收獲,下面我們一起來了解一下吧。
要了解協變與逆變,首先要引入:
根據 Liskov替換原則,如果C是P的子類,則P可以代替C,即 P p = new C();
C繼承于P,記做為 C < P
如果F是不變,當 C <= P 時,那么 F(C) 和 F(P) 沒有任何繼承關系
除例如 Integer是 Number的子類,根據 Liskov替換原則
Number number = new Integer(1); //correct
但是如果這樣寫就會報錯
List<Number> list = new ArrayList<Integer>(1); //error
雖然 Number和 Integer存在繼承關系:Integer < Number, 但在Java里,泛型默認是不變的, 因此也可以看作為 List<Number>
和List<Integer>
不存在任何繼承關系
如果F是協變的,當 C <= P 時,那么 F(C) <= F(P)
Java 提供了一個extends來將不變轉為協變,例如:
List<? extends Number> list = new ArrayList<Integer>(1); //corrent
此時的List<? extends Number>
可以看作為ArrayList<Integer>
的父類
? extend Number
可以看作為一個類型范圍,表示Number的某一個子類
數組默認是協變的
Number[] numbers = new Integer[3];
如果F是逆變的,當 C <= P 時,那么 F(C) >= F(P)
Java 提供了一個super來將不變轉為協變,例如:
List<? super Number> list = new ArrayList<Object>(1); //corrent
此時的 List<? super Number>
可以看作為 ArrayList<Object>
的父類
首先,我們看看Collection.add的實現:
public interface List<E> extends Collection<E> { boolean add(E e); }
下面代碼將會報錯?? extends Number
與Integer
類型不匹配
List<? extends Number> list = new ArrayList<Integer>(); // correct list.add(Integer.valueOf(1)); //error
首先在調用add方法時,泛型E
自動變成了<? extends Number>
第二行報錯,也就是說? extends Number
不是Integer
的父類。這里要將 List<? extends Number>
是ArrayList<Integer>
的父類區分開。
? extends Number
可以看作為一個類型范圍中某一個類型,表示Number的某一個子類,但又沒明確是哪個子類,可能是Float,可能是Short,也可能是Integer的子類(Integer被final修飾,不可能有子類,這里只是一種假設情況),它只確定了它的上界為 Number,并沒有確定下界(有可能存在? extends Number
< Integer
),因此 ? extends Number
不是Integer
的父類
將上面代碼稍做修改就正確了:
List<? super Number> list = new ArrayList<Object>(); // correct list.add(Integer.valueOf(1)); //correct
首先因為逆變,List<? super Number>
是ArrayList<Object>
的父類,第一行正確。
第二行: ? super Number
是Integer
的父類,原因是:? super Number
表示Number的某一個父類,可能是Serializable
也可能是 Object
但不管是哪個,Number的父類一定是Integer的父類,因此第二行也正確
java.util.Collections的copy方法(JDK1.7)給了我們答案:
public static <T> void copy(List<? super T> dest, List<? extends T> src) { int srcSize = src.size(); if (srcSize > dest.size()) throw new IndexOutOfBoundsException("Source does not fit in dest"); if (srcSize < COPY_THRESHOLD || (src instanceof RandomAccess && dest instanceof RandomAccess)) { for (int i=0; i<srcSize; i++) dest.set(i, src.get(i)); } else { ListIterator<? super T> di=dest.listIterator(); ListIterator<? extends T> si=src.listIterator(); for (int i=0; i<srcSize; i++) { di.next(); di.set(si.next()); } } }
要從泛型類取數據時,用extends;
要往泛型類寫數據時,用super;
既要取又要寫,就不用通配符(即extends與super都不用)
private static <E> E getFirst(List<? extends E> list){ return list.get(0); } private static <E> void setFirst(List<? super E> list, E firstElement){ list.add(firstElement); } public static void main(String[] args) { List<Integer> list = new ArrayList<Integer>(); setFirst(list, 1); Number number = getFirst(list); }
以上就是“Java泛型之協變、逆變、extends與super選擇方法”這篇文章的所有內容,感謝各位的閱讀!相信大家閱讀完這篇文章都有很大的收獲,小編每天都會為大家更新不同的知識,如果還想學習更多的知識,請關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。