JAVA學習之泛型。本站提示廣大學習愛好者:(JAVA學習之泛型)文章只能為提供參考,不一定能成為您想要的結果。以下是JAVA學習之泛型正文
ArrayList<E>類定義和ArrayList<Integer>類引用中涉及的術語:
1、整個ArrayList<E>稱為泛型類型
2、ArrayList<E>中E稱為類型變量或類型參數
3、整個ArrayList<Integer>稱為參數化的類型
4、ArrayList<Integer>中的Integer叫類型參數的實例或實際類型參數
5、ArrayList<Integer>中的<>念typeof
6、ArrayList稱為原始類型
泛型(Generic type 或者 generics)是對 Java 語言的類型系統的一種擴展,以支持創建可以按類型進行參數化的類。可以把類型參數看作是使用參數化類型時指定的類型的一個占位符,就像方法的形式參數是運行時傳遞的值的占位符一樣。
JDK1.5 之前使用集合的問題
1 public static void testJDK5Befor(){ 2 List list=new ArrayList(); 3 list.add(1); 4 list.add(2); 5 list.add("abc"); 6 int a1=(int) list.get(1); 7 int a2=(int) list.get(2); 8 }
執行代碼在第7行出現錯誤 Exception in thread "main" java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer
JDK1.5 對集合加入了泛型的概念,直接在編譯階段驗證數據類型。
1 public static void testJDK5After(){ 2 List<Integer> list=new ArrayList<Integer>(); 3 list.add(1); 4 list.add(2); 5 list.add("abc"); 6 }
第5行在編寫時直接報錯,提醒你:The method add(Integer) in the type List<Integer> is not applicable for the arguments (String)
泛型的作用:泛型在編譯時期進行嚴格的類型檢查,消除了絕大多數的類型轉換。泛型在集合中使用廣泛,在JDK1.5之後集合框架就全部加入了泛型支持。在沒有使用泛型之前,我們可以往List集合中添加任何類型的元素數據,因為此時List集合默認的元素類型為Object,而在我們使用的時候需要進行強制類型轉換,這個時候如果我們往List中加入了不同類型的元素,很容易導致類型轉換異常。
二、泛型擦除泛型只作用於編譯階段,在編譯階段嚴格檢查類型是否匹配,類型檢查通過後,JVM會將泛型的相關信息擦出掉(即泛型擦除),也就是說,成功編譯過後的class文件中是不包含任何泛型信息的,泛型信息不會進入到運行時階段。
public static void testMain01(){ ArrayList <String> listStr=new ArrayList<String>(); ArrayList <Integer> listInt=new ArrayList<Integer>(); System.out.println(listInt.getClass()==ArrayList.class);//true System.out.println(listStr.getClass()==listInt.getClass());//true }
通過該例子我們可以看出泛型在編譯為.class文件,加載到內存中後是沒有泛型概念的。
1、通過泛型的該特性我們可以使用反射繞過泛型檢查向集合中添加任意類型的數據
public static void testMain02() throws Exception{ ArrayList <Integer> listInt=new ArrayList<Integer>(); listInt.add(123); //我們要往該集合內添加其他類型的數據 listInt.getClass().getMethod("add", Object.class).invoke(listInt, "string"); System.out.println(listInt.size());//2 System.out.println(listInt.get(1));//string }三、泛型使用中出現的問題
//參數化類型與原始類型的兼容性-編譯警告 Collection<String> = new Vector(); //原始類型可以引用一個參數化類型的對象。 Collection = new Vector<String >(); //參數化類型不考慮類型參數的繼承關系 Vector<String> v = new Vector<Object>(); //錯! Vector<Object> v = new Vector<String>();//錯! //在創建數組實例時,數組的元素不能使用參數化的類型 Vector<Integer> v[] = new Vector<Integer>[10]; //編譯可以通過!因為編譯器只會按行解釋 Vector v1 = new Vector<Integer>(); Vector<Object> v = v1;四、泛型的?通配符及擴展 <?>可以引用各種參數化的類型,可以調用與參數無關的方法,不能調用與參數有關的方法
/** * 遍歷任意集合 * @param collection */ public static void printCollection(Collection<?> collection){ //System.out.println(collection.add("aa")); System.out.println(collection.size()); for(Object obj:collection){ System.out.println(obj); } }
限定通配符的上邊界
正確:Vector<? extends Number> v=new Vector<Integer>();表示 該泛型類型必須是number類型或者其子類類型
錯誤:Vector<? extends Number> v=new Vector<String>();
限定通配符的下邊界
正確:Vector<? super Integer> v=new Vector<Number>();表示 該泛型類型必須是Integer類型或者Integer的父類類型
錯誤:Vector<? extends Integer > v=new Vector<Byte>();
//采用自定義泛型的方式打印出任意參數類型中的所有元素 private static<T> void printCollection(Collection<T> collection,T obj2 ){ for(T obj : collection){ System.out.println(obj); } collection.add(obj2); } //定義一個 方法,可以將任意類型的某個數組填充為相應類型的某個對象 private static<T> void fillArray(T[] a,T obj){ for(int i=0;i<a.length;i++){ a[i] = obj; } } //定義一個 方法,自動將Object類型的對象轉換成其它類型 private static<T> T autoConvert(Object obj){ return (T)obj; }六、自定義泛型類
1 package com.jalja.org.base.test; 2 3 import java.util.Date; 4 5 public class GenericDao { 6 public <T> void add(T t){ 7 8 } 9 public <T> T findById(int id){ 10 return null; 11 } 12 13 public static void main(String[] args) { 14 GenericDao gd=new GenericDao(); 15 gd.add(new Date()); 16 String str=gd.findById(12); 17 } 18 }
一般在DAO中,每個DAO操作的是同一個數據類型,而在本例的15行添加date類型,在16行確返回了一個string類型,我們如何控制我們的dao操作的是同一類型呢,使用泛型類
1 package com.jalja.org.base.test; 2 3 import java.util.Date; 4 5 public class GenericDao <T>{ 6 public void add(T t){ 7 System.out.println(t.getClass()); 8 } 9 public T findById(int id){ 10 return null; 11 } 12 13 public static void main(String[] args) { 14 GenericDao<Date> gd=new GenericDao<Date>(); 15 gd.add(new Date()); 16 String str=(String) gd.findById(12); 17 } 18 }
在這裡會發現16行出錯,Cannot cast from Date to String 。應為你必須操作同一類型 date
泛型類中的靜態方法:
package com.jalja.org.base.test; import java.util.Date; public class GenericDao <T>{ public void add(T t){ System.out.println(t.getClass()); } public T findById(int id){ return null; } //泛型中不能出現與泛型類相關的靜態方法,應為靜態方法是作用於類級別的,與具體類的實例對象沒有關系。 //如果使用類名調用,泛型類型參數T是無法確定具體類型的所以,這樣不可以。 public static void update(T t){ } //可以定義與泛型類的泛型類型參數無關的靜態方法 public static <E> void update(E e){ } }