一、 泛型:
l 泛型目的就是要維護「型別」的安全性,讓建構集合(set)時的錯誤能在編譯期間就抓到,不會等執行時才發生錯誤。
l 例如使用ArrayList時,因為可以塞入不同的object進去,當我們取出來時都會是Object的型別,很容易造成混淆。
l 例如我們要呼叫dog的eat(),但dog、cat、fish動作都不一樣,但從ArrayList中取出來都是object,object根本不認識eat(),就算轉型,也會造成不知道該物件到底是dog or cat。
l 透過泛型,可以限定裡面能存放的物件型別,若加入其他物件皆能馬上發現,不會到執行期間才發生問題。
Public class ArrayList<E> extends AbstracList<E> implements List<E>…{
Public Boolean add(E o){…}
}
上面程式碼中的E是用來建構與初始ArrayList的型別,若我們宣告時使用ArrayList<String>,那String會取代所有宣告成E的位置。
Public <T extends Animal>void takeThing(ArrayList<T> list)
-------------------------------------------------------------------------------
Public void takeThing(ArrayList<Animal> list)
上面兩行的宣告方式意思不同,第一個T extends Animal代表說,這個T可以是extends或implements Animal的subClass,但是第二個代表傳入的只能是Animal。
l 因此要讓ArrayList中的Object進行sort時,可使用Collections.sort來進行,但此methods的宣告是<T extends Comparable>void takeThing,因此ArrayList中的物件必需要extends或implements Comparable才行。
l 除了讓該Class extends或implements之外,也可以額外建立一個class專門做這個動作,當需要Collections的處理時,再一起把兩個class放進來即可,此方法較好管理。
二、 Set集合的關係
List:負責處理順序
Set:重視獨一無二,不允許資料重覆
Map:透過Key來找資料,資料可以重覆但Key不行
l 之前所採用的ArrayList就是List的一種,重視資料的順序,若要讓資料是獨一無二的話,必需採用Set來進行。
l 在用歌曲(song)為例,歌名不能夠重覆,可以改用HashSet來做。
l 但是物件的重覆,比對時是採用hashCode,因此若要用equals()來比對物件,必需Override hashCode和equals兩個methods。
l 若兩個物件都是參考的同一個物件的話(指標指向同一物件),則hashcode計會相同。
Public boolean equals(Object song){
Return getTitle().equals(song.getTitle());
}
l 以上方法就可以用equals來判斷兩個物件是否相同,但是一般來說,物件相同代表hashCode也要相同,只Override hashCode是不夠的(對於Set來說兩者皆要相同才可以)。
Public int hashCode(){
Return title.hashCode();
}
l 若想要set不重覆又要可排序,可以用TreeSet,他擁有自動排序之功能,但缺點在於不需排序時,用此set會影響效能。同理,TreeSet會自動排序,因此加進去的class必需要extends或implements Comparable。
三、 Map:
l Map是依照key的方式來加入資料,key不可重覆,但指向的物件可以相同。
l 因為map需要一個Key,因此需要兩個型別參數<String, Integer>,string是key;int是值
HashMap<String, Integer> scores = new HashMap<String, Integer>();
l 因為map需要一個Key,因此需要兩個型別參數
四、 泛型與參數的問題
l 若我們用以下方法宣告,代表該AarrayList可以加入有extends Animal的subclass。
ArrayList<Animal> animal = new ArrayList<Animal>();
Public void takeAnimal(ArrayList<Animal> animals){
For(Animal a : animals)
}
l 依照多型概念,應該可以傳入ArrayList<dog>進去,但是在此會發生error。
l 因為如果傳入ArrayList<dog>進去,對於function來說是ArrayList<Animal>,是可以在ArrayList<Animal>加入一個cat,但這就會產生問題,我們對ArrayList<dog>加入了一個cat物件,雖然可以通過編譯但執行會發生錯誤。
Public void takeAnimal(ArrayList<? extends Animal> animals){
For(Animal a : animals)
}
l 用以上方法可以限定,function中的ArrayList不準加入任何物件。
Public <T extends Animal>void takeThing(ArrayList<T> list)
等於
Public void takeAnimal(ArrayList<? extends Animal> animals)
l 至於?跟T是沒有什麼區別的,但如果function中有兩個參數皆是用同一個型別的話,用T的方式可以比較簡潔。
Public <T extends Animal>void takeThing(ArrayList<T> list,ArrayList<T> two)
