java零基礎(chǔ)入門-高級特性篇(五) 泛型? 上
前面說集合的時候藐唠,有一個往List添加元素的方法add(E e)帆疟,說這個 E 叫泛型,可以表示任何一種類型宇立。為什么往集合添加元素的時候需要泛型踪宠?因為上一章的集合示例過于理想化,人為制造了一個前提妈嘹,就是認(rèn)為往集合里添加元素都是同樣的類型柳琢。但是理想很豐滿,現(xiàn)實很骨感润脸,如果對于一個集合添加的元素沒有約束柬脸,可以隨意往一個集合里面放任何類型的對象,會發(fā)生意想不到的問題毙驯。
為什么有泛型
雙十一你剁手了沒倒堕?每到雙十一,我們唯一的目標(biāo)就是清空購物車爆价,拿起你的手機(jī)垦巴,買買買~好了媳搪,作為一個程序員,這里從代碼的眼光出發(fā)骤宣,看看購物車這個神奇的東西秦爆。
首先有一個集合,就是購物車憔披,用來放商品對象等限。商品的屬性有名稱,價格活逆,類別。然后新建一個商品拗胜,再丟進(jìn)購物車蔗候,我忘了看價格,需要拿出來看看價格埂软,看如何實現(xiàn)锈遥。
為什么這個關(guān)鍵步驟需要進(jìn)行強(qiáng)制轉(zhuǎn)換類型?你寫上面代碼的時候可以試試不強(qiáng)制轉(zhuǎn)會會發(fā)生什么勘畔。如果不轉(zhuǎn)換所灸,cart.get(0)這個地方拿出的對象是Object類型,無法獲取到price這個屬性的值炫七。不對呀爬立!我放進(jìn)去的明明就是一個商品類型Commodity呀,為什么拿出來的時候變成Object了万哪?不好意思侠驯,購物車不夠智能,并不能記錄每一個你放進(jìn)購物車的東西是什么類型奕巍,他只能通通當(dāng)成Object處理了吟策,因為Object是所有類型的父類,不管你放啥進(jìn)購物車的止,他肯定是個Object檩坚。
這里雖然看個價格很麻煩,還要轉(zhuǎn)換類型诅福,但是終歸能看到類型匾委。但是接下來發(fā)生的情況就不那么簡單了。正當(dāng)我開開心心買買買的時候氓润,突然發(fā)現(xiàn)剩檀,哎喲~不錯喲~居然有的商品還有贈品!真是開心的不得了旺芽。贈品的屬性有名稱沪猴,類別辐啄。看代碼运嗜。
先看運行結(jié)果是什么壶辜。
Exception in thread "main" java.lang.ClassCastException: com.java.lesson14.Present cannot be cast to com.java.lesson14.Commodity
at com.java.lesson14.Shopping2.main(Shopping2.java:24)
這是啥玩意?不是應(yīng)該輸出兩個價格嗎担租?這個東西叫異常砸民,異常就是程序發(fā)生了錯誤,程序給出的錯誤信息奋救×氩危看看錯誤信息說了啥,ClassCastException尝艘,這個異常叫做類型轉(zhuǎn)換異常演侯。Present cannot be cast to?Commodity,意思是Present類型不能轉(zhuǎn)換成Commodity類型背亥,最后一行是出現(xiàn)錯誤的位置秒际,Shopping2.java:24 ,24行發(fā)生了類型轉(zhuǎn)換錯誤狡汉。
來看看24行發(fā)生了什么娄徊,為什么出現(xiàn)類型轉(zhuǎn)換錯誤。24行將第二個加入到集合的元素轉(zhuǎn)換成Commodity類型盾戴,原來往購物車添加?xùn)|西的時候寄锐,第一個是商品,第二個是贈品,24行將贈品轉(zhuǎn)為商品類型,就發(fā)生了錯誤比被。
為什么寫代碼的時候不報錯呢?運行才報錯呢沿癞?因為我們只設(shè)置了一個購物車,沒有規(guī)定購物車?yán)锩娣攀裁囱矫剩瑳]有規(guī)定當(dāng)然什么都可以放椎扬,扔個贈品進(jìn)去也很正常啊。運行的時候具温,要從購物車?yán)锩鎸|西拿出來蚕涤,上個例子看到,拿出來的時候是不知道這個東西是個什么類型的铣猩,統(tǒng)一認(rèn)為是Object揖铜。完蛋,我不知道哪個要轉(zhuǎn)換成商品類型达皿,哪個要轉(zhuǎn)換成贈品類型天吓,類型轉(zhuǎn)換發(fā)生錯誤可想而知贿肩。
這里使用的是List集合,可以按照順序來判斷類型龄寞,但是換成了Set汰规,那就是真的不知道要轉(zhuǎn)什么類型了。
問題出現(xiàn)了物邑,往集合里面放東西溜哮,拿出來的時候可能會發(fā)生錯誤,集合沒有記錄我扔進(jìn)去元素的類型色解,拿出來又只給我Object茂嗓,這下如何是好?
現(xiàn)在科阎,終于輪到本章主角隆重登場了述吸。
泛型是什么
沒有泛型的時候,集合就是個強(qiáng)迫癥患者萧恕,什么強(qiáng)迫癥刚梭?元素類型不統(tǒng)一就不能清空購物車肠阱,不能清空購物車就渾身難受票唆,心浮氣躁,上躥下跳屹徘。而泛型的出現(xiàn)走趋,恰恰治好了集合的強(qiáng)迫癥。為了能夠清空購物車噪伊,當(dāng)我們新建購物車的時候簿煌,就立下字據(jù),這個購物車只能放商品鉴吹,不是商品通通不讓放姨伟。如何實現(xiàn)?
List cart = new ArrayList();? ?//沒有立字據(jù)豆励,什么都可以放
List<Commodity> cart = new ArrayList<Commodity>();? //立字據(jù)夺荒,只能放Commodity類型的東西進(jìn)購物車
這里的<Commodity>就是泛型。表示這個集合只能放Commodity類型的元素良蒸。你敢放其他類型元素技扼,我就敢報錯。
一旦給集合加上了泛型嫩痰,在編譯的時候剿吻,就會判斷元素類型是否允許加入到集合,就不會出現(xiàn)上面那種只有在運行期才知道類型不對的錯誤了串纺。但是贈品不能添加到購物車怎么辦丽旅?總不能把贈品丟掉吧椰棘,舍不得呀,沒關(guān)系魔招,把贈品變成商品就行晰搀,價格設(shè)置為0。
上面的例子有點小小的問題办斑,但是我不打算改外恕,正好拿來復(fù)習(xí)前面的知識點。一個屬性設(shè)置為常量需要在前面加上static和final這兩個關(guān)鍵字乡翅,并且變量名全部大寫鳞疲。上面例子中這個常量其實是沒有起到作用的,因為在shopping3這個類中蠕蚜,將鉛筆這個贈品強(qiáng)制轉(zhuǎn)換到父類商品尚洽,調(diào)用getPrice()方法是獲取父類中的price屬性,并不是子類贈品里面這個設(shè)置為0的常量靶累。如果要獲取子類價格這個常量0腺毫,需要修改2個地方。第一挣柬,Present類添加getPrice這個方法潮酒,返回常量PRICE。第二邪蛔,Shopping3類強(qiáng)制轉(zhuǎn)換的時候急黎,將第二個元素強(qiáng)制轉(zhuǎn)換為子類Present,這樣打印的時候使用的就是子類PRICE常量侧到。
集合不加泛型是可以的勃教,但是如果元素類型不一致,強(qiáng)迫癥犯了渾身難受匠抗。所以建議使用集合的時候都要加上泛型故源,這樣不僅治好了強(qiáng)迫癥,還能夠使代碼更加健壯汞贸,不會有太多的隱患绳军,不然bug滿天飛小心飯碗不保。
泛型的語法變化
在java5的時候著蛙,有了泛型治好了集合的強(qiáng)迫癥删铃,List,Set踏堡,Map都可以使用泛型來規(guī)范元素的類型猎唁。但是有個缺點就是寫起來太啰嗦了。List和Set還好,Map寫起來真的是手要抽筋诫隅。
Map<String,Object> map = new HashMap<String,Object>();
是不是有個問題腐魂,在定義map的時候就寫了,我這個map元素的key-value類型是:key用String逐纬,value是Object蛔屹,為什么在實現(xiàn)的時候還要再寫一遍?在java7之前豁生,不好意思兔毒,你還真得老老實實寫一遍,但是java7的出現(xiàn)甸箱,可以讓我們偷偷懶了育叁。不需要在實現(xiàn)的時候再寫一遍泛型類型。
Map<String,Object> map = new HashMap<>();
后面只需要一對<>括號即可芍殖,java會根據(jù)前面的定義豪嗽,自己來推斷這里的泛型是什么類型。是不是更先進(jìn)更智能了豌骏。
集合里的泛型是泛型使用最廣泛的地方龟梦,除了治好了集合的強(qiáng)迫癥,泛型還有很多其他的用處窃躲,下期繼續(xù)计贰。