本文講述以下幾個(gè)方面的內(nèi)容,試圖說明泛型類型的子類及通配符的使用。
(1) 子類及替換原則;
(2) 使用extends關(guān)鍵字的通配符;
(3) 使用super關(guān)鍵字的通配符;
(1) 子類及替換原則
在java語言中,我們通俗講一個(gè)類是另一個(gè)類的子類型,是通過使用extends關(guān)鍵字去繼承某一個(gè)類或者使用implements關(guān)鍵字去實(shí)現(xiàn)某些接口。這樣我們?cè)诰幊虝r(shí)就可以面向接口或基類進(jìn)行編程,如:
Number num1 = new Integer(1);
Number num2 = new Double(2.1d);
這個(gè)就是所謂的替換原則,替換原則的定義是:
Substitution Principle: a variable of a given type may be assigned a value of any subtype of that type, and a method with a parameter of a given type may be invoked with an argument of any subtype of that type.
大概的意思是說某種類型的變量可以被該類型的任何子類所賦值,一個(gè)方法中的參數(shù)也可以被該參數(shù)的任何子類進(jìn)行調(diào)用。
現(xiàn)在我們?cè)賮砜纯捶盒椭刑鎿Q原則的適用性:
Example2.1
List listNums = new ArrayList();
nums.add(10);
nums.add(8.88);
在example2.1 中,可以看出替換原則被很好地應(yīng)用在這里,ArrayList是List的子類,我們提供給listNums變量的類型參數(shù)為Number,往 listNums中添加元素時(shí),10被封箱為Integer類型,而Integer是Number的子類,第三行的情況類似。
Example2.2
List intList = new ArrayList();
List numList = intList; //compile error
…
numList.add(1.35); // can‘t do that
根據(jù)替換原則,我們會(huì)很容易想到,既然Integer是Number的子類,則我們應(yīng)該可以將List的變量賦給 List的變量,但從實(shí)際情況表明,List并不是List的子類。
我們不妨試想想,若果List類型的變量可以成功賦值給List類型的變量,會(huì)出現(xiàn)什么情況?我們可能在程序的某個(gè)位置添加一個(gè)double類型的元素進(jìn)去numList中,而實(shí)質(zhì)上在numList中其它元素都是Integer 的類型的元素,這樣就違背了泛型的初衷了。
有時(shí),我們確實(shí)希望將形如List的List對(duì)象賦給List的變量,這時(shí)就要使用extends關(guān)鍵字的通配符。
(2) 使用extends關(guān)鍵字的通配符
Example2.3
List intList = new ArrayList();
List<? extends Number> numList = intList();
…
numList.add(1.35); //compile error (can‘t do that)
從Example2.3看到numList這個(gè)變量,我們可以將類型參數(shù)為Number及其Number子類的List賦給它。
記住一條規(guī)則如果你使用了“? extends T”,一般情況下,你不能往該數(shù)據(jù)結(jié)構(gòu)中put元素,而你可以做的就是get元素。
如果要往內(nèi)put元素,就需要使用下面提到的super關(guān)鍵字的通配符。
(3) 使用super關(guān)鍵字的通配符
Example2.4
List intList = new ArrayList List<? super Integer> numList = intList;
numList.add(3); //can put integer or null
在example2.4 我們可以看到<? super Integer>的意思為,我們可以將類型參數(shù)為Integer或Integer超類的List賦給 numList變量,并且可以put元素到列表中(注意:在該例子中put進(jìn)的元素只能為Integer或null類型)。
一條比較通用的規(guī)則:如果要往List中put元素則用<? super T>,如果要從List中g(shù)et元素則用<? extends T>,如果既要get又要put則不使用通配符。
(1) 子類及替換原則;
(2) 使用extends關(guān)鍵字的通配符;
(3) 使用super關(guān)鍵字的通配符;
(1) 子類及替換原則
在java語言中,我們通俗講一個(gè)類是另一個(gè)類的子類型,是通過使用extends關(guān)鍵字去繼承某一個(gè)類或者使用implements關(guān)鍵字去實(shí)現(xiàn)某些接口。這樣我們?cè)诰幊虝r(shí)就可以面向接口或基類進(jìn)行編程,如:
Number num1 = new Integer(1);
Number num2 = new Double(2.1d);
這個(gè)就是所謂的替換原則,替換原則的定義是:
Substitution Principle: a variable of a given type may be assigned a value of any subtype of that type, and a method with a parameter of a given type may be invoked with an argument of any subtype of that type.
大概的意思是說某種類型的變量可以被該類型的任何子類所賦值,一個(gè)方法中的參數(shù)也可以被該參數(shù)的任何子類進(jìn)行調(diào)用。
現(xiàn)在我們?cè)賮砜纯捶盒椭刑鎿Q原則的適用性:
Example2.1
List
nums.add(10);
nums.add(8.88);
在example2.1 中,可以看出替換原則被很好地應(yīng)用在這里,ArrayList是List的子類,我們提供給listNums變量的類型參數(shù)為Number,往 listNums中添加元素時(shí),10被封箱為Integer類型,而Integer是Number的子類,第三行的情況類似。
Example2.2
List
List
…
numList.add(1.35); // can‘t do that
根據(jù)替換原則,我們會(huì)很容易想到,既然Integer是Number的子類,則我們應(yīng)該可以將List
我們不妨試想想,若果List
有時(shí),我們確實(shí)希望將形如List
(2) 使用extends關(guān)鍵字的通配符
Example2.3
List
List<? extends Number> numList = intList();
…
numList.add(1.35); //compile error (can‘t do that)
從Example2.3看到numList這個(gè)變量,我們可以將類型參數(shù)為Number及其Number子類的List賦給它。
記住一條規(guī)則如果你使用了“? extends T”,一般情況下,你不能往該數(shù)據(jù)結(jié)構(gòu)中put元素,而你可以做的就是get元素。
如果要往內(nèi)put元素,就需要使用下面提到的super關(guān)鍵字的通配符。
(3) 使用super關(guān)鍵字的通配符
Example2.4
List
numList.add(3); //can put integer or null
在example2.4 我們可以看到<? super Integer>的意思為,我們可以將類型參數(shù)為Integer或Integer超類的List賦給 numList變量,并且可以put元素到列表中(注意:在該例子中put進(jìn)的元素只能為Integer或null類型)。
一條比較通用的規(guī)則:如果要往List中put元素則用<? super T>,如果要從List中g(shù)et元素則用<? extends T>,如果既要get又要put則不使用通配符。