Java 泛型(二) 泛型之中的通配符(Wildcards)使用


泛型之中的通配符(Wildcards)使用

 

限制泛型可用類型

  在定義泛型類別時,預設可以使用任何的類型來實例化泛型類型中的類型。

  但是如果想限制使用泛型類別時,只能用某個特定類型或者是其子類型才能實例化該類型時,可以在定義類型時,使用extends關鍵字指定這個類型必須是繼承某個類,或者實現某個接口,也可以是這個類或接口本身。

  比如下面的例子:

  

import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;

public class ListGenericFoo<T extends List>
{
    private T[] fooArray;

    public T[] getFooArray()
    {
        return fooArray;
    }

    public void setFooArray(T[] fooArray)
    {
        this.fooArray = fooArray;
    }
    
    public static void main(String[] args)
    {
        ListGenericFoo<LinkedList> foo1 = new ListGenericFoo<LinkedList>();
        ListGenericFoo<ArrayList> foo2 = new ListGenericFoo<ArrayList>();
        
        //Error: Bound mismatch
        //ListGenericFoo<HashMap> foo3 = new ListGenericFoo<HashMap>();
        
        LinkedList[] linkedLists = new LinkedList[10];
        foo1.setFooArray(linkedLists);
        
        ArrayList[] arrayLists = new ArrayList[10];
        foo2.setFooArray(arrayLists);
        
    }

}

 

  類聲明中:public class ListGenericFoo<T extends List>

  這樣就規定了T必須是一個List繼承體系中的類,即實現了List接口的類。

  此處注意,雖然List是一個接口,但是關鍵字仍然是extends而不是implements。

  並且這個List也可以后加括號指明類型,如List<String>等。

  當沒有指定泛型繼承的類型或接口時,默認使用T extends Object,所以默認情況下任何類型都可以作為參數傳入。

 

  當不使用泛型時,比如那些聲明時帶有<T>的集合類型,如果使用時沒有指定類型,泛型類別為Object。不會報錯,但是會有警告。

  <? extends SomeClass>是一個限界通配符(bounded wildcard)代表了一個未知的類型,並且它是SomeClass的子類,也可以是SomeClass本身。

  這里面SomeClass是統配符的上界(upper bound of the wildcard)。

  相應的也有限定下界的,使用關鍵字super

  通配符所代表的其實是一組類型,但具體的類型是未知的。

 

類型通配聲明

  看下面的代碼:

    GenericFoo<Integer> foo1 = null;
     GenericFoo<Boolean> foo2 = null;
     //此時foo1只能接受GenericFoo<Integer>類型的實例,foo2只能接受GenericFoo<Boolean>類型的實例

          

  如果希望有一個變量foo可以指向下面所有的實例:

      //foo = new GenericFoo<ArrayList>();

      //foo = new GenericFoo<LinkedList>();

  可以這樣聲明:

    GenericFoo<? extends List> foo = null;

    foo = new GenericFoo<ArrayList>();

    foo = new GenericFoo<LinkedList>();

 

  注意這種形式不同於前面的限制泛型可用類型時提到的形式。

  前面提到的形式是在聲明泛型的類的時候限制了可以用的泛型類型,而現在這種形式是在使用的時候限制了引用的類型,使得引用指向繼承了某一個類或接口的類型。

  如果該應用指向其他類型,則會編譯報錯:

    //Error:Type mismatch
    foo = new GenericFoo<HashMap>();

 

  也可以限制引用指向某個類或接口的繼承層次之上的類或接口:

  比如:        

    //引用指向繼承層次之上
   GenericFoo<? super List> ge= null;
   ge = new GenericFoo<Object>();

 

  使用<?>或是<? extends SomeClass>的聲明方式,意味着您只能通過該名稱來取得所參考的實例的信息,或者是移除某些信息,但不能增加或者改寫它的信息。

  因為只知道當中放置的是SomeClass的子類,但不確定是什么類的實例,編譯器不讓您加入信息,理由是,如果可以加入信息的話,那么您就得記得取回的是什么類型的實例,然后轉換為原來的類型方可進行操作,這樣就失去了使用泛型的意義。

  另,GenericFoo<? extends Object>等價於GenericFoo<?>,但是它們與GenericFoo<Object>不同,因為GenericFoo<Object>限定了類型為Object。

 

參考資料  

  張龍老師Java SE視頻教程。

  The Java Tutorials : Lesson: Generics (Updated)

  http://docs.oracle.com/javase/tutorial/java/generics/index.html

  Lesson: Generics

  http://docs.oracle.com/javase/tutorial/extra/generics/index.html

  Wildcards

  http://docs.oracle.com/javase/tutorial/extra/generics/wildcards.html

  Java深度歷險值Java泛型

  http://kb.cnblogs.com/page/93005/

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM