泛型方法VS類(lèi)型通配符(兩者可以混用):
1)你會(huì)發(fā)現(xiàn)所有能用類(lèi)型通配符(?)解決的問(wèn)題都能用泛型方法解決众弓,并且泛型方法可以解決的更好:
最典型的一個(gè)例子就是:
a. 類(lèi)型通配符:void func(List<? extends A> list);
b. 完全可以用泛型方法完美解決:<T extends A> void func(List<T> list);
上面兩種方法可以達(dá)到相同的效果(?可以代表范圍內(nèi)任意類(lèi)型谓娃,而T也可以傳入范圍內(nèi)的任意類(lèi)型實(shí)參)滨达,并且泛型方法更進(jìn)一步俯艰,?泛型對(duì)象是只讀的,而泛型方法里的泛型對(duì)象是可修改的画株,即List<T> list中的list是可修改的@卜!
2) 要說(shuō)兩者最明顯的區(qū)別就是:
i. ?泛型對(duì)象是只讀的续挟,不可修改充边,因?yàn)?類(lèi)型是不確定的浇冰,可以代表范圍內(nèi)任意類(lèi)型聋亡;
ii. 而泛型方法中的泛型參數(shù)對(duì)象是可修改的,因?yàn)轭?lèi)型參數(shù)T是確定的(在調(diào)用方法時(shí)確定)漂佩,因?yàn)門(mén)可以用范圍內(nèi)任意類(lèi)型指定;
注意投蝉,前者是代表瘩缆,后者是指定,指定就是確定的意思庸娱,而代表卻不知道代表誰(shuí),可以代表范圍內(nèi)所有類(lèi)型归露;
3) 這樣好像說(shuō)的通配符?一無(wú)是處斤儿,但是并不是這樣,Java設(shè)計(jì)類(lèi)型通配符?是有道理的玄捕,首先一個(gè)最明顯的優(yōu)點(diǎn)就是?的書(shū)寫(xiě)要比泛型方法簡(jiǎn)潔枚粘,無(wú)需先聲明類(lèi)型參數(shù)飘蚯,其次它們有各自的應(yīng)用場(chǎng)景:
i. 一般只讀就用?,要修改就用泛型方法攀圈,例如一個(gè)進(jìn)行修改的典型的泛型方法的例子:
public <T> void func(List<T> list, T t) {
list.add(t);
}
ii. 在多個(gè)參數(shù)峦甩、返回值之間存在類(lèi)型依賴(lài)關(guān)系就應(yīng)該使用泛型方法凯傲,否則就應(yīng)該是通配符?:
具體講就是,如果一個(gè)方法的返回值幌缝、某些參數(shù)的類(lèi)型依賴(lài)另一個(gè)參數(shù)的類(lèi)型就應(yīng)該使用泛型方法诫欠,因?yàn)楸灰蕾?lài)的類(lèi)型如果是不確定的?浴栽,那么其他元素就無(wú)法依賴(lài)它)典鸡,例如:<T> void func(List<? extends T> list, T t); 即第一個(gè)參數(shù)依賴(lài)第二個(gè)參數(shù)的類(lèi)型(第一個(gè)參數(shù)list的類(lèi)型參數(shù)必須是第二個(gè)參數(shù)的類(lèi)型或者其子類(lèi))椿每;
可以看到英遭,Java支持泛型方法和' ? '混用;
這個(gè)方法也可以寫(xiě)成:<T, E extends T> void func(List<E> list, T t); // 明顯意義是一樣的汁尺,只不過(guò)這個(gè)list可以修改多律,而上一個(gè)list無(wú)法修改。
總之就是一旦返回值辽装、形參之間存在類(lèi)型依賴(lài)關(guān)系就只能使用泛型方法拾积;
否則就應(yīng)該使用' ? '
4) 對(duì)泛型方法的類(lèi)型參數(shù)進(jìn)行規(guī)約:即有時(shí)候可能不必使用泛型方法的地方你不小心麻煩地寫(xiě)成了泛型方法丰涉,而此時(shí)你可以將其規(guī)約成使用?的最簡(jiǎn)形式
i. 總結(jié)地來(lái)講就是一句話(huà):只出現(xiàn)一次 & 對(duì)它沒(méi)有任何依賴(lài)
ii. 例如:<T, E extends T> void func(List<T> l1, List<E> l2); // 這里E只在形參中出現(xiàn)了一次(類(lèi)型參數(shù)聲明不算),并且沒(méi)有任何其他東西(方法形參肛度、返回值)依賴(lài)它承耿,那么就可以把E規(guī)約成?
N泵骸!最終規(guī)約的結(jié)果就是:<T> void func(List<T> l1, List<? extends T> l2);
5) 一個(gè)最典型的應(yīng)用就是容器賦值方法(Java的API):public static <T> void Collections.copy(List<T> dest, List<? extends T> src) { ... }
K蟆蝙砌!從src拷貝到dest,那么dest最好是src的類(lèi)型或者其父類(lèi)择克,因?yàn)檫@樣才能類(lèi)型兼容,并且src只是讀取壹堰,沒(méi)必要做修改贱纠,因此使用?還可以強(qiáng)制避免你對(duì)src做不必要的修改响蕴,增加的安全性
————————————————
版權(quán)聲明:本文為CSDN博主「tom和cat」的原創(chuàng)文章,遵循 CC 4.0 BY-SA 版權(quán)協(xié)議辖试,轉(zhuǎn)載請(qǐng)附上原文出處鏈接及本聲明劈狐。
原文鏈接:https://blog.csdn.net/sinat_32023305/article/details/83215751