泛型除了KTV,還有一個讓人比較疑惑的玩意,而且它就是用來表達疑惑的:?
雖然通過泛型已經達到我們想要的效果了,例如:
List<String> list = new ArrayList<String>();
這樣就可以放心地存取String型別的資料,
但是(抱歉,凡事總有個但是),應用的場景總是在不斷增加的,某一天:
老板:咱們之前給客戶開發的功能中有個地方要改一改,
神牛:哪里要改呢?
老板:以前你寫的代碼List<Cat> list = new ArrayList<Cat>();只能列出Java寵物店托管的貓咪,但是現在Java寵物店已經擴大了經營范圍,希望列出他們保管所有的寵物,只要是寵物就行......
神牛:這個easy!
老板:真的嗎?
于是,神牛一通操作,代碼就改成了這樣:
class Cat extends Pets {}; class Dog extends Pets {}; public static void main(String[] args) { List<? extends Pets> list = new ArrayList<Pets>(); Pets pets = list.get(0); Cat cat = (Cat)list.get(1); Dog dog = (Dog)list.get(2); }
然鵝,過了一段時間,Java寵物店由于經營不善,已經將之前的寵物轉賣、送人了一部分,現在就剩一些貓科動物,所以現在的寵物籠子需要重新分配,只要是貓科動物就要往里放,以前寫的代碼
List<? extends Pets> list = new ArrayList<Pets>();
就滿足不了給寵物分配籠子的需求了(先想一想為啥不行了?)
神牛繼續把鍵盤一頓猛敲,代碼又改成了這樣:
class Felidae {}; class Cat extends Felidae {}; public static void main(String[] args) { List<? super Felidae> list = new ArrayList<Felidae>(); Cat cat = new Cat(); list.add(cat); }
這樣一改,以前的功能又不能用了(為啥不能列出保管的寵物了?)
從以上需求場景可以看到:
1、對于不確定或者不關心實際要操作的型別,可以使用無界通配符(尖括號里一個問號,即 <?>),表示可以持有任何型別;
2、<? extends T>稱之為「上界通配符」,表示只允許T及T的子類呼叫,例如只允許寵物類Pets的子類Cat和Dog呼叫;
3、<? super T>剛好相反,稱之為「下界通配符」,表示只允許T及T的父類呼叫,例如只允許Cat的父類Felidae呼叫;
4、由于上界通配符<? extends T>中只知道T這個父類,而不知道具體的子類(所以用?代替),因此它無法實作向串列中加入新元素的功能,也就是做不到list.add()(這就是為什么滿足不了給寵物分配籠子的需求);
5、而由于下界通配符<? super T>中只知道T這個子類,而不知道具體的父類(所以用?代替),因此它無法實作從串列中獲取元素的功能,也就是做不到list.get()(這也是為什么滿足不了列出保管的寵物),
剛才說了那么多,稍稍有點繞,總結一下:
由于<? extends T>的只能取,不能存;而<? super T>得只能存,不能取,因此在架構設計中就有一個推薦的實踐經驗:
1、生產者producer一般用<? extends T>
2、消費者consumer一般用<? super T>
泛型講到這里,如果能夠全部明白,就可以真正暢快地去KTV嗨了,而泛型其他的知識點,像什么無界通配符、泛型引數一致性、多重限定、基類劫持介面、自限定型別、回圈泛型等亂七八糟的可以統統不去管了,因為很多工程師一輩子的職業生涯中幾乎都碰不到它們,除非點背到極點,還是最開始的那幾個建議:
1、不鉆牛角尖,有問題見招拆招
2、解決主要宏觀上、業務上的問題,暫時忽略次要的技術上的、細節上的問題
3、抓大放小,用好80/20原則
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/512968.html
標籤:Java
上一篇:SpringBoot+MyBatis Plus對Map中Date格式轉換的處理
下一篇:Docker 部署 Kibana
