java泛型(一)、泛型的基本介紹和使用

如今開始深刻學習Java的泛型了,之前一直只是在集合中簡單的使用泛型,根本就不明白泛型的原理和做用。泛型在java中,是一個十分重要的特性,因此要好好的研究下。 1、泛型的基本概念 泛型的定義:泛型是JDK 1.5的一項新特性,它的本質是參數化類型(Parameterized Type)的應用,也就是說所操做的數據類型被指定爲一個參數,在用到的時候在指定具體的類型。這種參數類型能夠用在類、接口和方法的建立中,分別稱爲泛型類、泛型接口和泛型方法。 泛型思想早在C++語言的模板(Templates)中就開始生根發芽,在Java語言處於尚未出現泛型的版本時,只能經過Object是全部類型的父類和類型強制轉換兩個特色的配合來實現類型泛化。例如在哈希表的存取中,JDK 1.5以前使用HashMap的get()方法,返回值就是一個Object對象,因爲Java語言裏面全部的類型都繼承於java.lang.Object,那Object轉型爲任何對象成都是有可能的。可是也由於有無限的可能性,就只有程序員和運行期的虛擬機才知道這個Object究竟是個什麼類型的對象。在編譯期間,編譯器沒法檢查這個Object的強制轉型是否成功,若是僅僅依賴程序員去保障這項操做的正確性,許多ClassCastException的風險就會被轉嫁到程序運行期之中。 泛型技術在C#和Java之中的使用方式看似相同,但實現上卻有着根本性的分歧,C#裏面泛型不管在程序源碼中、編譯後的IL中(Intermediate Language,中間語言,這時候泛型是一個佔位符)或是運行期的CLR中都是切實存在的,List<int>與List<String>就是兩個不一樣的類型,它們在系統運行期生成,有本身的虛方法表和類型數據,這種實現稱爲類型膨脹,基於這種方法實現的泛型被稱爲真實泛型。 Java語言中的泛型則不同,它只在程序源碼中存在,在編譯後的字節碼文件中,就已經被替換爲原來的原始類型(Raw Type,也稱爲裸類型)了,而且在相應的地方插入了強制轉型代碼,所以對於運行期的Java語言來講,ArrayList<int>與ArrayList<String>就是同一個類。因此說泛型技術其實是Java語言的一顆語法糖,Java語言中的泛型實現方法稱爲類型擦除,基於這種方法實現的泛型被稱爲僞泛型。(類型擦除在後面在學習) 使用泛型機制編寫的程序代碼要比那些雜亂的使用Object變量,而後再進行強制類型轉換的代碼具備更好的安全性和可讀性。泛型對於集合類來講尤爲有用。 泛型程序設計(Generic Programming)意味着編寫的代碼能夠被不少不一樣類型的對象所重用。java

實例分析: 在JDK1.5以前,Java泛型程序設計是用繼承來實現的。由於Object類是所用類的基類,因此只須要維持一個Object類型的引用便可。就好比ArrayList只維護一個Object引用的數組: [java] view plain copy public class ArrayList//JDK1.5以前的
{
public Object get(int i){......}
public void add(Object o){......}
......
private Object[] elementData;
}
這樣會有兩個問題: 一、沒有錯誤檢查,能夠向數組列表中添加類的對象 二、在取元素的時候,須要進行強制類型轉換 這樣,很容易發生錯誤,好比: [java] view plain copy /*jdk1.5以前的寫法,容易出問題/
ArrayList arrayList1=new ArrayList();
arrayList1.add(1);
arrayList1.add(1L);
arrayList1.add("asa");
int i=(Integer) arrayList1.get(1);//由於不知道取出來的值的類型,類型轉換的時候容易出錯
這裏的第一個元素是一個長整型,而你覺得是整形,因此在強轉的時候發生了錯誤。程序員

因此。在JDK1.5以後,加入了泛型來解決相似的問題。例如在ArrayList中使用泛型: [java] view plain copy /** jdk1.5以後加入泛型*/
ArrayList<String> arrayList2=new ArrayList<String>(); //限定數組列表中的類型
// arrayList2.add(1); //由於限定了類型,因此不能添加整形
// arrayList2.add(1L);//由於限定了類型,因此不能添加整長形
arrayList2.add("asa");//只能添加字符串
String str=arrayList2.get(0);//由於知道取出來的值的類型,因此不須要進行強制類型轉換數組

還要明白的是,泛型特性是向前兼容的。儘管 JDK 5.0 的標準類庫中的許多類,好比集合框架,都已經泛型化了,可是使用集合類(好比 HashMap 和 ArrayList)的現有代碼能夠繼續不加修改地在 JDK 1.5 中工做。固然,沒有利用泛型的現有代碼將不會贏得泛型的類型安全的好處。安全

在學習泛型以前,簡單介紹下泛型的一些基本術語,以ArrayList<E>和ArrayList<Integer>作簡要介紹: 整個成爲ArrayList<E>泛型類型 ArrayList<E>中的 E稱爲類型變量或者類型參數 整個ArrayList<Integer> 稱爲參數化的類型 ArrayList<Integer>中的integer稱爲類型參數的實例或者實際類型參數 ·ArrayList<Integer>中的<Integer>念爲typeof Integer ArrayList稱爲原始類型框架

2、泛型的使用 泛型的參數類型能夠用在類、接口和方法的建立中,分別稱爲泛型類、泛型接口和泛型方法。下面看看具體是如何定義的。 一、泛型類的定義和使用 一個泛型類(generic class)就是具備一個或多個類型變量的類。定義一個泛型類十分簡單,只須要在類名後面加上<>,再在裏面加上類型參數: [java] view plain copy class Pair<T> {
private T value;
public Pair(T value) {
this.value=value;
}
public T getValue() {
return value;
}
public void setValue(T value) {
this.value = value;
}
}
如今咱們就可使用這個泛型類了: [java] view plain copy public static void main(String[] args) throws ClassNotFoundException {
Pair<String> pair=new Pair<String>("Hello");
String str=pair.getValue();
System.out.println(str);
pair.setValue("World");
str=pair.getValue();
System.out.println(str);
}ide

Pair類引入了一個類型變量T,用尖括號<>括起來,並放在類名的後面。泛型類能夠有多個類型變量。例如,能夠定義Pair類,其中第一個域和第二個域使用不一樣的類型: public class Pair<T,U>{......} 注意:類型變量使用大寫形式,且比較短,這是很常見的。在Java庫中,使用變量E表示集合的元素類型,K和V分別表示關鍵字與值的類型。(須要時還能夠用臨近的字母U和S)表示「任意類型」。學習

二、泛型接口的定義和使用 定義泛型接口和泛型類差很少,看下面簡單的例子: [java] view plain copy interface Show<T,U>{
void show(T t,U u);
}測試

class ShowTest implements Show<String,Date>{
@Override
public void show(String str,Date date) {
System.out.println(str);
System.out.println(date);
}
}
測試一下: [java] view plain copy public static void main(String[] args) throws ClassNotFoundException {
ShowTest showTest=new ShowTest();
showTest.show("Hello",new Date());
}this

三、泛型方法的定義和使用 泛型類在多個方法簽名間實施類型約束。在 List<V> 中,類型參數 V 出如今 get()、add()、contains() 等方法的簽名中。當建立一個 Map<K, V> 類型的變量時,您就在方法之間宣稱一個類型約束。您傳遞給 add() 的值將與 get() 返回的值的類型相同。 相似地,之因此聲明泛型方法,通常是由於您想要在該方法的多個參數之間宣稱一個類型約束。 舉個簡單的例子: [java] view plain copy public static void main(String[] args) throws ClassNotFoundException {
String str=get("Hello", "World");
System.out.println(str);
}.net

public static <T, U> T get(T t, U u) {  
    if (u != null)  
        return t;  
    else  
        return null;  
}

3、泛型變量的類型限定 在上面,咱們簡單的學習了泛型類、泛型接口和泛型方法。咱們都是直接使用<T>這樣的形式來完成泛型類型的聲明。 有的時候,類、接口或方法須要對類型變量加以約束。看下面的例子: 有這樣一個簡單的泛型方法: [java] view plain copy public static <T> T get(T t1,T t2) {
if(t1.compareTo(t2)>=0);//編譯錯誤
return t1;
}
由於,在編譯以前,也就是咱們還在定義這個泛型方法的時候,咱們並不知道這個泛型類型T,究竟是什麼類型,因此,只能默認T爲原始類型Object。因此它只能調用來自於Object的那幾個方法,而不能調用compareTo方法。 可個人本意就是要比較t1和t2,怎麼辦呢?這個時候,就要使用類型限定,對類型變量T設置限定(bound)來作到這一點。 咱們知道,全部實現Comparable接口的方法,都會有compareTo方法。因此,能夠對<T>作以下限定: [java] view plain copy public static <T extends Comparable> T get(T t1,T t2) { //添加類型限定
if(t1.compareTo(t2)>=0);
return t1;
}

類型限定在泛型類、泛型接口和泛型方法中均可以使用,不過要注意下面幾點: 一、無論該限定是類仍是接口,統一都使用關鍵字 extends 二、可使用&符號給出多個限定,好比 [java] view plain copy public static <T extends Comparable&Serializable> T get(T t1,T t2)

三、若是限定既有接口也有類,那麼類必須只有一個,而且放在首位置 [java] view plain copy public static <T extends Object&Comparable&Serializable> T get(T t1,T t2)

相關文章
相關標籤/搜索