我們在學習java的繼承規則時,已經知道任何需要父類型的地方,都可以被替換成子類型,現在我們有如下類的繼承結構:
- // 子類Student可以轉換成父類Person
- Student student = new Student();
- Person person = student;
然而泛型機制規定如下的轉換是錯誤的:
- // Erro: Type mismatch: cannot convert from Result<Student> to Result<Person>
- Result<Student> re_student = new Result<Student>(new Student(), new Student());
- Result<Person> re_person = re_student;
在泛型機制里無論S和T這兩個類是什么關系,Result<S>和Result<T>是沒有什么聯系的。
我們假設上述的泛型轉換是成功的,那么我們就可以通過re_person的引用,將Teacher類的相關信息設置到Result<Student> re_student這個對象中,這顯然是不允許的。
(一) 通配符類型------上界通配符<? extends T>
為了解決泛型這種使用起來的不便性,java泛型的設計者們引入了通配符"?"。
比如Result<? extends Person>表示任何泛型Result類型,它的類型參數是Person以及Person的子類,如Result<Student>。
我們將上述的泛型轉換改為如下形式:
- // Result<? extends Person>是Result<Student>的父類型
- Result<Student> re_student = new Result<Student>(new Student(), new Student());
- Result<? extends Person> re_person = re_student;
這種形式的轉換就是正確的,我們稱<? extends Person>為上界通配符。
然而使用上界通配符也帶來了一些副作用:
我們看如下的代碼:
- public static void main(String [] args){
- // Result<? extends Person>是Result<Student>的父類型
- Result<Student> re_student = new Result<Student>(new Student(), new Student());
- Result<? extends Person> re_person = re_student;
- Person person = re_person.getCode();
- //Error:The method setCode(capture#2-of ? extends Person) in the type Result<capture#2-of ? extends Person> is not
- //applicable for the arguments (Student)
- re_person.setCode(new Student);
- }
看起來域的訪問器setCode()方法無法使用
re_person.setCode(new Student);// Error
Result<? extends Person>的方法看起來是如下這樣的:
- ? extends Person getCode() {
- return code;
- }
- void setCode(? extends Person code) {
- this.code = code;
- }
setCode的形參是? extends Person code,但是不知道具體是什么類型這樣就無法傳遞特定的類型,也就無法調用setCode()方法了,畢竟通配符"?"不能匹配具體的任何類型。
而getCode()是能正常調用的,我們知道? extends Person代表的是Person的子類,這樣我們就可以把get到的值轉換成父類型Person。
(二) 通配符類型------下界通配符<? super T>
在上面中我們說,當使用上界通配符<? extends T>時,只能get數據而不能set數據;而下界通配符<? super T>剛好相反,當使用下界通配符時,只能set數據而不能get數據。
<? super Student> 表示將通配符限制為Student或者及其超類,如下圖所示:
當使用Result<? super Student>下界通配符時,其方法看起來是這樣的:
- ? super Student getCode() {
- return code;
- }
- void setCode(? super Student code) {
- this.code = code;
- }
對於set操作我們已經知道形式參數是Student或者Student的超類
那么我們就可以使用小於等於Student粒度的類型來傳遞參數
對於get操作 我們只知道返回值是Student或者Student的超類 但具體是什么類型我們不知道 所有我們無法
給具體的類進行賦值;只能賦值給Object對象
- public static void main(String [] args){
- // Result<? super Student>為下界通配符
- Result<Student> re_student = new Result<Student>(new Student(), new Student());
- Result<? super Student> sre_student = re_student;
- // Error:The method setCode(capture#4-of ? super Student) in the type Result<capture#4-of ? super Student> is not
- // applicable for the arguments (Person)
- sre_student.setCode(new Person());
- // right operation
- // 對於set操作我們已經知道形式參數是Student或者Student的超類
- // 那么我們就可以使用小於等於Student粒度的類型來傳遞參數
- sre_student.setCode(new Graduate());
- sre_student.setCode(new Master());
- // Error:Type mismatch: cannot convert from capture#5-of ? super Student to Student
- // 對於get操作 我們只知道返回值是Student或者Student的超類 但具體是什么類型我們不知道 所有我們無法
- // 給具體的類進行賦值;只能賦值給Object對象
- Student student = sre_student.getCode();
- // right operation
- Object object = sre_student.getCode();
- }
(三) 總結限定通配符的使用
<? extends T>:上界通配符 只能取數據而不能寫入數據
<? super T> : 下界通配符 只能寫入數據 取數據只能賦值給Object
如果你既想要獲取數據,又要寫入數據,那么你不能使用通配符類型變量,你可以嘗試使用固定的類型變量T,如果還不能解決你的問題,
那么不建議你使用泛型解決你的這個問題。