哈嘍大家好芒篷,我是阿Q!
事情是這個(gè)樣子的......
對(duì)話中的截圖如下:
看了阿Q的解釋采缚,你是否也和“馬小跳”一樣存在疑問呢针炉?請(qǐng)往??看
我們都知道在java
中,只要是類型兼容扳抽,就可以將一種類型的對(duì)象分配給另一種類型的對(duì)象篡帕。比如可以將一個(gè)Integer
類型的對(duì)象分配給Object
類型的對(duì)象殖侵,因?yàn)?code>Object 是Integer
的超類。
Object someObject = new Object();
Integer someInteger = new Integer(10);
someObject = someInteger; //OK
在面向?qū)ο笾辛眨覀儼阉Q之為 is a 的關(guān)系拢军。因?yàn)?code>Integer是Object
的一種子類,所以允許被賦值怔鳖。
又因?yàn)?code>Integer也是Number
的一種子類茉唉,所以下邊的代碼也是有效的:
public void someMethod(Number n) { /* ... */ }
someMethod(new Integer(10)); // OK
someMethod(new Double(10.1)); // OK
當(dāng)然泛型也是如此,在執(zhí)行泛型類型調(diào)用時(shí)结执,將Number
作為其類型參數(shù)傳遞度陆,如果參數(shù)是Number
的子類型靶溜,則允許任何后續(xù)的add
調(diào)用:
Box<Number> box = new Box<Number>();
box.add(new Integer(10)); // OK
box.add(new Double(10.1)); // OK
現(xiàn)在我們來看以下代碼:
public void boxTest(Box<Number> n) { /* ... */ }
該方法接收什么類型的參數(shù)呢绪氛?
通過該方法,大家肯定知道它的參數(shù)類型為Box<Number>
犀呼,但是大家思考一個(gè)問題:你認(rèn)為Box<Integer>
和Box<Double>
類型的參數(shù)可以傳入嗎蜡感?
答案是否定的蹬蚁。
盡管Integer
是Number
的子類型,但Box<Integer>
和Box<Double>
不是Box<Number>
的子類郑兴,它倆的父類對(duì)象是Object
犀斋。文首的對(duì)話表達(dá)的就是這個(gè)意思。
那么問題來了杈笔,當(dāng)類的泛型相關(guān)時(shí)闪水,如何在兩個(gè)泛型類之間創(chuàng)建類似子類型的關(guān)系呢?例如如何讓Box<Integer>
和Box<Double>
變得與Box<Number>
有關(guān)呢蒙具?
為了搞懂這個(gè)問題球榆,我們先來了解一下同一類型的對(duì)象是如何實(shí)現(xiàn)子類型化的吧。
通過分析源碼我們可以發(fā)現(xiàn):ArrayList<E>
實(shí)現(xiàn)了 List<E>
禁筏,List<E>
繼承了Collection<E>
持钉,所以ArrayList<String>
是List<String>
的子類型, List<String>
是 Collection<String>
的子類型篱昔。因此當(dāng)我們?cè)趥鬟f參數(shù)時(shí)每强,ArrayList<String>
類型的是可以給List<E>
或者Collection<E>
傳遞的。
只要不改變類型參數(shù)州刽,類型之間的子類型關(guān)系就會(huì)保留空执。
如果我們想要定義我們自己的列表接口PayloadList
,使得泛型類型P的可選值與每個(gè)元素相關(guān)聯(lián)穗椅,可以定義如下:
interface PayloadList<E,P> extends List<E> {
void setPayload(int index, P val);
...
}
則PayloadList<String,String>
辨绊、PayloadList<String,Integer>
、PayloadList<String,Exception>
都是List<String>
的子類型匹表。
小結(jié):可以通過繼承泛型類或者實(shí)現(xiàn)接口來對(duì)其進(jìn)行子類型化门坷。
搞懂了子類型化的問題宣鄙,我們回到“如何在兩個(gè)泛型類之間創(chuàng)建類似子類型的關(guān)系“的問題。
泛型類或者接口并不會(huì)僅僅因?yàn)樗鼈兊念愋椭g有關(guān)系而變得相關(guān)默蚌,如果要達(dá)到相關(guān)冻晤,我們可以使用通配符來創(chuàng)建泛型類或接口之間的關(guān)系。
Box<Integer>
和Box<Number>
的父類對(duì)象其實(shí)是Box<?>
為了在這些類之間創(chuàng)建關(guān)系绸吸,以便代碼可以通過Box<Integer>
訪問Box<Number>
的方法鼻弧,可以使用上限通配符:
Box<? extends Integer> initBox = new Box<>();
Box<? extends Number> numberBox = initBox;
// OK. Box<? extends Integer> is a subtype of Box<? extends Number>
因?yàn)?code>Integer是Number
的子類型,numberBox
的泛型是Number
對(duì)象子類惯裕,所以在intBox
和numberBox
之間存在關(guān)系温数。
圖為用上限和下限通配符聲明的幾個(gè)類之間的關(guān)系绣硝。
所以蜻势,“馬小跳”的問題你會(huì)了嗎?還不會(huì)的話來技術(shù)群交流吧鹉胖!