天天看點

黑馬程式員_泛型(Generic)

--------------- android教育訓練、java教育訓練、期待與您交流! --------------

一,泛型的基礎知識

jdk1.5之後出現的新特性

泛型是提供給javac編譯器使用的,它可以限定集合中輸入的類型,讓編譯器擋住源程式中的非法輸入,編譯器編譯帶類型的說明的集合時會去除掉"類型"資訊,是程式運作效率不受影響。對應參數化的泛型類型,getClass()方法的傳回值和原始類型完全一樣。由于編譯生成的位元組碼會去掉泛型的類型資訊,隻要能跳過編譯器,就可以往某個泛型集合中加入其他類型的資料。例如用反射得到的集合,再調用add方法即可。

泛型是編譯器看的,是以通過反射可以避過編譯器,繼續把不同的類型的值放進已經被泛型限定了的集合裡面。

以ArrayList<E>為例

ArrayList稱為原始類型,<>譯為"typeof",ArrayList<E>稱為泛型類型,E稱為類型變量或者類型參數;

ArrayList<String>稱為參數化的類型,String稱為類型參數的執行個體或實際類型參數

參數化類型與原始類型全部相容Vector v = new Vector<String>();或者:Vector<String> v = new Vector();都可以。

參數化類型不考慮類型參數的繼承問題。也就是說泛型類型中的類型參數,等号兩邊隻要不是同一種,那麼編譯就一定不會通過。

為什麼在建立數組執行個體時,數組的元素不能使用參數化的類型?

編譯器是嚴格按照步驟走的。它檢測每一行代碼的資訊是否有誤,但是不會用執行時候的答案來檢測代碼的正确性。

二,泛型限定:

泛型的通配符(?)應用:?表示任意類型。比如當要定義一個任意參數化類型的集合(Collection<?> col),就用得到了通配符。

使用?通配符可以引用其他各種參數化的類型,?通配符定義的變量主要用作引用,可以調用與參數化無關的方法,不能調用與參數化有關的方法。比如集合中的add()方法,使用了?的集合就不能在調用這個方法。

public void printCollection(Collection<?> col){}

也就是說Collection<?> col = new ArrayList<String>();編譯器讓這個表達式被編譯通過。

泛型的限定:

?extends E:可以接收E類型或者E的子類。這是上限限定

?super E:可以接收E類型或者E的父類。這是下限限定

三,自定義泛型

要定義一個泛型,必須在函數的傳回值之前用尖括号括起來

1、//這樣聲明的範型可以代替任意類型資料我們市場用到的鍵值對Map.Entry<K,V>不就是給予範型的嗎

  KV都可以代替任意類型的值,但是在java中範型的實際類型必須是引用類型

<K,V> void get(K k,V v)

{

}

  2、Java中的範型不能像C++那麼靈活

<T>  T  add(T a,T b)

{

   //return  a+b   ;//很多人以為java也想C++一樣可以這樣 ,但是不可以 。    

return  null;

}

  這個傳回的null也是有類型限制的,比如上面的ab分别是Integer和String那麼就會取他們共同的基類Object做為傳回值類型,其他的同理

  3、實作任意類型的數組的成員值的交換,注意在自定義範型中範型的實際類型隻能是引用資料類型不能是基本資料類型

public  static <T> void  swap(T[]a,int x,int y)

{

  T  tem  =a[x]  ;

  a[x]=a[y]  ;

  a[y]=tem ;

}

  上面這個方法如果我  swap(new Integer[]{1,2,3,4,5},1,2);       //這樣就會自動交換下标12的值

  但是這樣調用就錯了   swao(new int[]{1,2,3,5,6},2,3) ;  //是以說Java的範型的實際類型 隻能是引用資料類型

  4、<T  extends  String>     表示類型隻能是String或者String的派生類

    <T super  String >   表示範型類型隻能是String或者String的父類

   用法同3

  5、下面這個函數利用範型來實作類型自動轉換的功能

public static  <T> T autoConvert(Object obj)  //因為傳回值是 T辨別任意類型 所喲可以 将傳回結果指派給任意類型對象

{

  return (T)obj;

}

Object  obj==”";

String str=autoConvert(obj);

  可以完成自動轉換,因為範型T代表任意類型,是以他可以指派給String類型的對象

6、将任意類型的對象填充到任意類型的數組中,與是fillArray(newInteger[]{2,3,4},”ddd”);這樣調用是正确的,這樣做忽略類型限制

public  static <T> void  fillArray(T[] a,T b)  //将任意一個對象填充到任意類型的數組

{

  for(int i =0;i<a.length;i++)

  {

   a[i] =b ;

  }

}

  7、以自定義範型的形式顯示一個集合的資料,下面一個是利用自定義範型一個是利用通配符來實作,但是不同的是利用通配符操作的集合不能向集合中插入元素。

  但是自定義範型卻可以。原因是通配符代表的集合我們不知道集合内部具體元素是什麼類型是以不能對集合進行add操作。

public static  <T> void showCollection(Collection<T> col,T  obj)  //利用範型來輸出任意類型集合

  col.add(obj) ;

  for(T a:col)

  {

   System.out.println(a);

  }

}

public static void showCollection(Collection<?> col)  //利用範型來輸出任意類型集合

  for(Object obj:col)

  {

   System.out.println(obj);

  }

}

  8、如果一個類中多個方法都需要範型那麼就是用類級别的範型。例如

class  A<E> 

     public void  add(E obj){}

     public  E  get(){} 

     private E data; 

}

  這樣聲明範型和在函數前面聲明其實是一樣的隻不過是在類的級别上作用于整個類而已

  9、要注意範型隻是給編譯器看的。

  也就是說Vector<Integer>Vector<String>他們用到的都是同一份位元組碼,位元組碼隻有class檔案加載到記憶體中的時候才有

  是以在一個類中下面2個方法不能同時存在

void show(Vector<Integer>) {}

void show(Vector<String>){}

四,通過反射獲得泛型的參數化類型

jdk1.5開始,一個方法可以通過反射擷取到他的參數的參數化類型比如:put(Vector<Date> v),通過反射可以擷取Date的類型

1.Method裡面的方法:

Type[] getGenericParameterTypes()

按照聲明順序傳回描述了此 Method 對象所表示的方法的形參類型的 Type 對象的數組。

Type getGenericReturnType()

傳回表示由此 Method 對象所表示方法的正式傳回類型的 Type 對象。

2.Type是接口,是ParameterizedType的父類

3.ParameterizedType 參數化類型 它放的是泛型的參數化類型執行個體

Type[] getActualTypeArguments()

傳回表示參數的類的的類型參數的Type對象數組。

Type getOwnerType()

傳回 Type 對象,傳回此類的頂層類的類型。比如O<T>.I<S>,則傳回 O<T> 的表示形式

Type getRawType()

傳回 Type 對象,表示聲明此類型的類或接口。

---------------------- android教育訓練、java教育訓練、期待與您交流! ----------------------

詳細請檢視:http://edu.csdn.net/heima