JAVA-泛型

JAVA泛型


1.概述

泛型:即“參數化類型”。將類型由原來的具體類型參數化,類似於方法中的變量參數,此時類型同樣定義爲參數形式,只有在調用/運行時才傳入具體的類型。

泛型的本質:爲了參數化類型,即在不創建新的類型的情況下,通過反省制定的不同類型來控制形參具體顯限制的類型,也就是說在使用泛型的過程中,操作的數據類型被指定爲某一參數時,改類型可以用在泛型類、泛型接口、泛型方法中。

2.特性

泛型只在編譯階段有效--->由於JVM的泛型類型擦除。

    List<String> l1 = new ArrayList<String>();
    List<Integer> l2 = new ArrayList<Integer>();

    /*輸出結果爲true*/
    System.out.println(l1.getClass() == l2.getClass());

在編譯過程中,驗證泛型的類型正確性之後,將相關信息擦除。即泛型類型在編譯階段看似多個不同的類型,實際在編譯之後的階段,都是相同的基本類型。

3.泛型的使用

  • 泛型類
  • 泛型接口
  • 泛型方法

3.1 泛型類

通過泛型可以完成對一組類的操作對外開放相同的接口,典型有各種容器類:List、Set、Map等。

泛型類的基本寫法:

    class 類名 <泛型標識>{
      /*該處T(泛型標識)由外部制定*/
      private 泛型標識 成員變量名;

      /**
      *@param 自定義
      *@return 返回泛型標識類型的類型 
      */
      public 泛型標識 成員變量名(@param T t){}
    }


泛型標識:可以寫爲任意標識,常見的如T、E、K、V。
實例化泛型類時,必須制定T的具體類型(包括自定義類),不能使簡單類型(如int、double)。

3.2 泛型接口

泛型接口常被用在各種類的生產器中。

泛型接口的基本寫法:

    public interface 接口名<泛型標識/*這裏用T*/>{
      public T 方法名();
    }

    /**
     *未傳入泛型實參時,與泛型類的定義相同,在聲明類的時候,需將泛型的聲明也一起加到類中
     *如不聲明,編譯器報錯:"Unknown class"
     */
    class ImplGenerator<T> implements Generator<T>{
      @override
      public T next(){
        return null;  
      }
    }

3.3 泛型通配符

如:

    public void showKetValue(Geberic<?> obj){
                Log.d("泛型測試","key value is " + obj.getKey());
    }


類型通配符一般是使用?代替具體的類型實參。和Integer、String一樣都是一種實際的類型。

使用場景:可以解決當具體類型不確定的時候,這個通配符就是?;當操作類型時,不需要使用類型的具體功能時,只是用Object類中的功能,那麼可以用?通配符來表示未知類型。

3.4 泛型方法

大多數泛型類中的成員方法也是用了泛型,甚至有的泛型類中包含着泛型方法,學習時要注意區分。

泛型類:在實例化類的時候指明泛型的具體類型;泛型方法:在調用方法的時候指明泛型的具體類型。
泛型方法可出現在任意地方和任意場景中使用。

泛型方法的基本寫法:

    /**
     *@param t 傳入泛型實參
     *@return T 返回類型爲T
     *說明:
     *1)只有聲明瞭public和返回類型中間的<T>纔是泛型方法
     *2)<T>表示四該方法將使用的泛型類型爲T,諸如T、E、K等,該T可出現在泛型方法任意位置
     *3)Class<T>中的T表示爲該類的泛型類型
     *4)泛型的數量也可以爲任意多個
     *如:
     *public <T,K> K showKeyName(Generic<T> container){...}
     */    
     public <T> genericMethod(Class<T> t) throws InstantiationException,
      IllegalAccessExceotion{
        T instance = t.newInstance();
        return instance;
      }

3.4.1 泛型方法與可變函數

如:

    public <T> void printMsg(T...args){
      for(T t:args){
        Log.d("Test"," t is " + t);
      }
    }

3.4.2 靜態方法與泛型

類中的靜態方法使用泛型:靜態方法無法訪問類上定義的泛型,方法操作的引用數據類型不確定的時候,必須要將泛型定義在該靜態方法上

如:

    public class StaticGenerator<T> {
    ....
    /**
     *如果在類中定義使用泛型的靜態方法,需要添加額外的泛型聲明(將這個方法定義成泛型方法)
     *即使靜態方法要使用泛型類中已經聲明過的泛型也不可以。
     *如:public static void show(T t){..},此時編譯器會提示錯誤信息:
          "StaticGenerator cannot be refrenced from static context"
     */
    public static <T> void show(T t){}
    }

3.4.3 泛型方法總結

泛型方法可獨立於類產生變化,基本原則如下:

無論何時,如果能做到,就儘量使用泛型方法,也就是說,如果使用泛型方法將整個類泛型化,那麼就應該使用泛型方法。另外,對於一個static的方法,無法訪問泛型類型的參數。所以如果要事static方法使用泛型能力,就必須使其成爲泛型方法。

4. 泛型的上下邊界

  • 添加上邊界,即傳入的類型實參必須是指定參數或其子類型
    public void showKeyValue(Generic<? extends Number> obj){}
  • 添加下邊界,即傳入的類型實參必須是制定參數或其父類
    public void showKeyValue(Generic<? super Integer> obj){}
  • 無邊界,即通配符?,參看"3.3泛型通配符"

例子:

    //在泛型方法中添加上下邊界限制的時候,必須在權限聲明與返回值之間的<T>上添加上下邊界,即在泛型聲明的時候添加
    //public <T> T showKeyName(Generic<T extends Number> container),編譯器會報錯:"Unexpected bound"
    public <T extends Number> T showKeyName(Generic<T> container){
      System.out.println("container key :" + container.getKey());
      T test = container.getKey();
      return test;
    }

:泛型的上下邊界添加,必須與泛型的聲明在一起

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章