菜鳥學Java(二十二)——重新認識泛型

劉水鏡發表於2014-10-28

泛型是Java SE 1.5的新特性,泛型的本質是引數化型別,也就是說所操作的資料型別被指定為一個引數。這種引數型別可以用在類、介面和方法的建立中,分別稱為泛型類、泛型介面、泛型方法。 Java語言引入泛型的好處是安全簡單。


規則和限制

1、泛型的型別引數只能是類型別(包括自定義類),不能是簡單型別。
2、同一種泛型可以對應多個版本(因為引數型別是不確定的),不同版本的泛型類例項是不相容的。
3、泛型的型別引數可以有多個。
4、泛型的引數型別可以使用extends語句,例如<T extends superclass>。習慣上稱為“有界型別”。
5、泛型的引數型別還可以是萬用字元型別。例如Class<?> classType = Class.forName("java.lang.String")。


限制泛型
我們一般是這樣定義泛型的:class Generics<T>,實際上這裡的限定型別相當於Object,這和“Object泛型”實質是一樣的。什麼是限制比如我們要限制T為集合介面型別。只需要這麼做:class Generics<T extends Collection>,這樣類中的泛型T只能是Collection介面的實現類,傳入非Collection介面編譯會出錯。

注意:<T extends Collection>這裡的限定使用關鍵字extends,後面可以是類也可以是介面。但這裡的extends已經不是繼承的含義了,應該理解為T型別是實現Collection介面的型別,或者T是繼承了XX類的型別。


public class CollectionGen<T extends Collection> {
    private T t;
    
    public CollectionGen(T t) {
        this.t = t;
    }
        
    public T getT() {
        return t;
    }

    public void setT(T t) {
        this.t = t;
    }


    public static void main(String args[]) {
        CollectionGen<ArrayList> genList = null;
        genList = new CollectionGen<ArrayList>(new ArrayList());
        
        //以下程式碼不能通過編譯
//        CollectionGen<Collection> genCollention = null;
//        genCollention=new CollectionGen<ArrayList>(new ArrayList());
        System.out.println("可以編譯通過並執行!");
    }
}

 


上面的程式碼是可以編譯通過併成功執行的。但是開啟註釋掉的兩行就出錯了,因為<T extends Collection>這麼定義型別的時候,就限定了構造此類例項的時候T是確定的一個型別,這個型別實現了Collection介面。簡單一句話就是:上面這種方式,定義跟例項化的型別必須完全一致。


萬用字元泛型
為了解決型別被限制死了不能動態根據例項來確定的缺點,引入了“萬用字元泛型”,針對上面的例子,使用通配泛型格式為<? extends Collection>,“?”代表未知型別,這個型別是實現Collection介面。那麼上面實現的方式可以寫為:

public static void main(String args[]) {
        Generics<ArrayList> genList = null;
        genList = new Generics<ArrayList>(new ArrayList());
        
        //以下程式碼可以通過編譯
        Generics<? extends Collection> genCollention = null;
        genCollention=new Generics<ArrayList>(new ArrayList());
        System.out.println("可以編譯通過並執行!");
    }

 


1、如果只指定了<?>,而沒有extends,則預設是允許Object及其下的任何Java類了。也就是任意類。
2、萬用字元泛型不單可以向下限制,如<? extends Collection>,還可以向上限制,如<? super Double>,表示型別只能接受Double及其上層父類型別,如Number、Object型別的例項。
3、泛型類定義可以有多個泛型引數,中間用逗號隔開,還可以定義泛型介面,泛型方法。這些都與泛型類中泛型的使用規則類似。


多介面限制
雖然Java泛型簡單的用 extends 統一的表示了原有的 extends 和 implements 的概念,但仍要遵循應用的體系,Java 只能繼承一個類,但可以實現多個介面,所以你的某個型別需要用 extends 限定,且有多種型別的時候,只能存在一個是類,並且類寫在第一位,介面列在後面,也就是:<T extends SomeClass & interface1 & interface2 & interface3>

這裡的例子僅演示了泛型方法的型別限定,對於泛型類中型別引數的限制用完全一樣的規則,只是加在類宣告的頭部,如:

public class Demo<T extends Comparable & Serializable>{
        //T型別就可以用Comparable宣告的方法和Seriablizable所擁有的特性了
    }


最後再強調一點,就是泛型最重要的作用就是提高了程式碼的安全性,因為它能夠在編譯期對程式碼進行檢查,從而避免了很多在執行期強轉型別發生的異常。瞭解了泛型出現的目的,相信你也就知道該怎麼使用泛型了吧!
    

相關文章