標籤:list 系統 類型 萬用字元 設計 資料 高效 解決 end
1.為什麼要使用泛型(generic)程式設計?
在《Java核心技術》中的闡述:編寫的代碼可以被許多不同類型的對象所重用,這樣就允許泛型代碼和遺留代碼之間能夠相互操作。
提到的兩個概念:型別參數、萬用字元類型
在《Head first Java》中的解釋似乎更通俗易懂些:幾乎所有以泛型編寫的程式都與處理集合有關,雖然泛型可以用在其他地方,但它主要目的還是讓你能夠寫成有型別安全的集合,也就是說編譯器能夠幫忙防止你把Dog加到一群Cat中。
就像在Collection類的sort方法中有寫明:public static <T extends Comparable<?super T>>void sort (List<T> list)其中Comparable<?super T>就是在對參數類型做限制,加入的是什麼對象,返回的還是該對象的引用。
在泛型功能出現前,編譯器無法注意到你加入集合中的東西是什麼,因為所有的集合都寫成處理Object類型,可以把任何東西放進ArrayList中,有點像ArrayList<Object>
在Java的程式或檔案中只要用到<>這組符號, 就表示泛型正在作用—它是一種從Java 5.0開始加入的特質。
ArrayList雖然是最常用的,但偶爾還是會有特殊情況,比如ArrayList沒有排序方法。下面列出幾個重要的:
LinkedList:針對經常插入或刪除中間元素所設計的高效率集合(實際上ArrayList還是比較實用)
TreeSet:以有序狀態保持並防止重複
(TreeSet的元素必須是Comparable
使用TreeSet,下列其中一項必須為真
集合中的元素必須是有實現Comparable的類型
使用重載,取用Comparator參數的建構函式來建立TreeSet
)
HashSet:防止重複的集合,可快速地找到相符的元素。(但是要override hashcode()和equals()這兩個方法)
HashMap:可用成對的name/value來儲存於取出
LinkedHashMap:類似HashMap,但是可記住元素插入的順序,也可以設定成按照元素上次存取的先後來排序。
關於泛型
1) 建立被泛型化類(例如ArrayList)的執行個體
建立ArrayList時你必須要指定它所容許的對象,就像單純的數組那樣。
new ArrayList<Song>()
2) 聲明與指定泛型型別的變數
多態遇到泛型型別會怎麼樣?
數組與ArrayList
對於ArrayList,如果把方法聲明成取用ArrayList<Animal>,它就智慧取用ArrayList< Animal >參數,ArrayList< Animal的子類>就行,而數組就可以實現。
數組的類型是在運行期間檢查的,但集合的類型檢查只會發生在編譯期間,所以如果出現類型錯誤,對於集合來說,編譯是都無法通過的。
泛型與多態
萬用字元?:用來接受Animal子型參數的方法
public void takeAnimals (ArrayList<? extends Animal> animals){ ……
}
extends同時代表繼承和實現
List<Song> songlist=new ArrayList<Song>()
1) 聲明(與調用)取用泛型型別的方法
聲明:void foo(List<Song> list)
調用x.foo(songList)
總結:主要就是泛型類,泛型變數,泛型方法。
註:API的設計團隊已經涵蓋了大部分你會遇到的額資料結構,而幾乎只有集合會真的需要泛型。
使用泛型的類
ArrayList是最常用的泛型化類型,我們從查看它的說明檔案說起。
public class ArrayList<E> extends Abstraction<E> implements List<E>…{
……
}
其中E就被稱為型別參數
運用泛型的方法
泛型的類代表類的聲明用到型別參數,泛型的方法代表方法的聲明特徵用到型別參數
在方法中的型別參數有幾種不同的運用方式:
1) 使用定義在類聲明的型別參數
public class ArrayList<E> extends AbstracList<E>…{
public boolean add(E o)
2) 使用未定義在類聲明的型別參數
public <T extends Animal> void takeThing(ArrayList<T> list)
代表傳入Animal或其子型來出初始化ArrayList。
從Collection的API說明檔案中我們發現3個主要的介面:List、Set和Map
LIST:對付順序的好幫手
是一種知道索引位置的集合,List知道某物在系列集合中的位置,可以有多個元素引用相同的對象。
SET:注重獨一無二的性質
不允許重複的集合。它知道某物是否已經存在於集合中,不會有多個元素引用相同的對象
MAP:用key來搜尋的專家
使用成對的索引值和資料值。Map會維護與key有關聯的值,兩個key可以引用相同的對象,但是key不能重複,典型的key是String,但也可以是任何對象。
集合的API
以上內容來自Head first Java,接下來的內容from 《Java核心技術》 (感覺該書闡述的有點抽象)
泛型程式設計分為3個能力等級:
1) 僅僅使用泛型類
2) 能夠利用Java泛型系統地解決代碼銜接,泛型類混合問題。
3) 實現自己的泛型類和泛型方法。
2.泛型類:具有一個或多個類型變數的類。
pair類引入了一個類型變數T,用角括弧<>括起來,並放在類名後面。
泛型類可以有多個類型變數,例如,也可以這樣定義pair類,其中第一個域和第二個域使用不同的類型:
public class Pair<T,U>{. . .}
3.泛型方法:
如下為定義一個帶有型別參數的簡單方法:
class ArrayAlg
{
public static <T> T getMiddle(T. . .a)
{
return a[a.length/2];
}
}
類型變數放在修飾符public static的後面,傳回型別的前面。
泛型方法可以定義在普通類中,也可以定義在泛型類中。
4.類型變數的限定
為類型變數實現介面,來達到限定的目的,避免產生編譯錯誤,如,為T實現Comparable介面
public static <T extends Comparable> T getMiddle(T. . .a)
類型擦除:去掉類型變數的限制,或者將類型變數替換為object
橋方法:為解決類型擦除與多態發生衝突的問題
有關Java泛型轉換的事實:
虛擬機器沒有泛型,只有普通的類和方法。
所有的參數類型都用它們的限定類型替換
橋方法被合成來保持多態
為保持型別安全,必要時插入強制類型轉換
【學習筆記】Java基礎知識——泛型與集合