泛型在Java集合中普遍使用,它是一種未知的數據類型,當不知道使用哪一種數據類型的時候,能夠使用泛型。泛型能夠看作一個變量,用來接收數據類型。如E e:表明Element 元素,T t:表明Type類型。好比ArrayList,定義集合時不知道里面會存儲什麼數據類型,定義ArrayList類源碼中,使用public class ArrayList<E>,裏面數據類型爲E, 而且裏面有兩個方法,一個參數類型爲E,一個返回數據類型爲E,這都是泛型的應用。html
public boolean add(E e)
public E get(int index)java
建立集合對象的時候,就會肯定泛型的數據類型,建立時是什麼數據類型,就以什麼樣的數據類型做爲參數傳遞到E,咱們也能夠使用泛型,用來本身建立類、方法和接口,感覺泛型的優勢,並瞭解泛型的通配符的上下限。 安全
集合定義時若是不使用泛型,就默認是Object類型,在作某些子類API調用時,可能不必定都適用集合裏全部的數據類型,可能會致使運行期報錯。若是建立集合使用泛型,則有效的規避了這樣的風險,將運行期出現的錯誤上升到了編譯期。ide
1 package GenericTest; 2 3 import javax.swing.text.html.HTMLDocument; 4 import java.util.ArrayList; 5 import java.util.Iterator; 6 7 /** 8 * 使用泛型的好處 9 */ 10 public class GenericDemo1 { 11 /** 12 * 建立集合對象若是不使用泛型,默認數據類型爲Object 13 * 優勢:數據類型爲Object,能夠存儲任意類型的數據 14 * 缺點:因爲存儲的數據類型能夠任意,在調用特有API時可能會引起異常 15 * <p> 16 * 若是建立集合對象的時候使用泛型 17 * 優勢:集合對象定義使用什麼數據類型,就是什麼數據類型,另外將運行期出現的問題上升到了編譯期,能夠提早發現問題 18 * 缺點:定義數據類型單一,準確來講應該是特色不是缺點 19 */ 20 21 public static void main(String[] args) { 22 //不使用泛型 23 //printArray(); 24 //使用泛型 25 printArrayWithGeneric(); 26 27 } 28 29 //集合不使用泛型 30 public static void printArray() { 31 ArrayList list = new ArrayList(); 32 list.add("hello my future!"); 33 list.add(8848); 34 //遍歷集合 35 Iterator it = list.iterator();//集合是什麼泛型,迭代器就是什麼泛型 36 //打印 OK 37 while (it.hasNext()) { 38 System.out.println(it.next()); 39 } 40 41 //若是想輸出集合元素字符串的長度,須要使用String的API,Object須要向下轉型爲String才能夠調用 42 Iterator it1 = list.iterator(); 43 while (it1.hasNext()) { 44 String str = (String) it1.next();//Object向下轉型爲String 45 int len = str.length(); 46 System.out.println(str + "-->" + len); 47 } 48 /** 49 * 打印輸出看出,當打印第一個字符串長度沒有問題,可是打印數字時出現了異常,報java.lang.Integer cannot be cast to java.lang.String 50 * 顯然是類型轉換出來問題,致使的報錯,所以若是不使用泛型,可能會出現調用特定API致使不適用而報錯 51 */ 52 53 } 54 55 //集合使用泛型 56 public static void printArrayWithGeneric() { 57 ArrayList<String> list = new ArrayList<String>();//集合對象數據類型爲String,則這個數據類型做爲參數傳遞給E 58 list.add("hello my future"); 59 /*list.add(8848);//編譯就報錯*/ 60 Iterator<String> it = list.iterator(); 61 while (it.hasNext()) { 62 System.out.println(it.next()); 63 } 64 65 } 66 67 }
控制檯輸出結果測試
當不使用泛型時,想調用String類型的API,致使數字轉換異常報錯,這就是不使用泛型的不安全性,當使用泛型其在編譯期就報錯。this
泛型能夠用來定義一個類,對應類中的方法參數和返回值等都要相應變成泛型類型。spa
1 package GenericTest; 2 3 /** 4 * 定義和使用含有泛型的類,模擬ArrayList集合定義,下面類定義一個參數,剛開始爲String,後面在類後面定義泛型後,方法參數所有定義爲泛型 5 */ 6 public class GenericClass<E> { 7 8 private E Parameter; 9 10 public E getParameter() { 11 return Parameter; 12 } 13 14 public void setParameter(E parameter) { 15 Parameter = parameter; 16 } 17 }
建立一個實體類來測試數據類型爲自定義,上面類方法的調用。3d
package GenericTest; /** * 自定義測試類,驗證定義含有泛型的類 */ public class Student { private String name; private int age; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public String toString() { return "Student{" + "name='" + name + '\'' + ", age=" + age + '}'; } }
測試類,方法使用時調用不一樣的數據類型,獲得不一樣測試結果。code
1 package GenericTest; 2 3 /** 4 * 測試定義含有泛型的類 5 */ 6 public class GenericClassTest { 7 8 public static void main(String[] args) { 9 //建立對象時,泛型類型爲String 10 GenericClass<String> col=new GenericClass<>(); 11 col.setParameter("hello my future"); 12 System.out.println(col.getParameter()); 13 //建立對象時,泛型類型爲Integer 14 GenericClass<Integer> col1=new GenericClass<>(); 15 col1.setParameter(8848); 16 System.out.println(col1.getParameter()); 17 //建立對象時,泛型類型爲自定義 18 GenericClass<Student> col2=new GenericClass<>(); 19 Student stu=new Student(); 20 stu.setName("clyang"); 21 stu.setAge(18); 22 col2.setParameter(stu); 23 System.out.println(col2.getParameter().toString()); 24 } 25 }
控制檯輸出狀況,能夠看出當你給方法什麼類型的參數它就使用什麼類型的參數執行方法,並返回對應的值。htm
定義和使用含有泛型的方法,泛型定義在方法修飾符和返回值之間,含有泛型的方法被調用時,往裏傳遞的是什麼參數,則泛型就是什麼類型的泛型。
格式:
方法修飾詞 <泛型> 返回值類型 方法名(參數類型(定義的泛型) 參數){
方法體
}
1 package GenericTest; 2 3 /** 4 * 定義和使用含有泛型的方法,泛型定義在方法修飾符和返回值之間 5 * 格式: 6 * 方法修飾詞 <泛型> 返回值類型 方法名(參數類型(定義的泛型) 參數){ 7 * 方法體 8 * } 9 * 10 * 含有泛型的方法被調用時,傳遞的是什麼參數則泛型就是什麼類型的泛型 11 */ 12 public class GenericMethod { 13 //定義一個普通方法 14 public <M> void printMethod1(M m) { 15 System.out.println(m); 16 } 17 18 //定義一個靜態方法 19 public static <N> void printMethod2(N n) { 20 System.out.println(n); 21 } 22 }
測試方法中使用泛型。
1 package GenericTest; 2 3 /** 4 * 測試方法中定義泛型 5 */ 6 public class GenericMethodTest { 7 8 public static void main(String[] args) { 9 //測試方法中定義泛型 10 GenericMethod gm = new GenericMethod(); 11 gm.printMethod1("hello my future"); 12 gm.printMethod1(8848); 13 gm.printMethod1(new Student()); 14 15 //測試方法中使用泛型 --靜態方法 16 //靜態方法調用不建議使用建立對象後使用,直接使用類名.方法名就能夠使用 17 GenericMethod.printMethod2("hello my good fate"); 18 GenericMethod.printMethod2(8848); 19 GenericMethod.printMethod2(new Student()); 20 } 21 }
控制檯輸出狀況,普通方法和靜態方法均可以實現正常調用。
接口中定義泛型,有兩種實現方法,一種是在實現類實現接口時,定義接口中泛型類型。另一種是實現類實現接口,接口是什麼泛型實現類就是什麼類型泛型,具體參考以下代碼。
1 package GenericTest; 2 3 /** 4 * 定義和使用含有泛型的接口 5 * 6 * 第一種實現方法:定義一個含有泛型的接口,再定義一個實現類來實現這個接口,實現時指定接口的泛型 7 * 或者好比Scanner類,public final class Scanner implements Iterator<String>,實現Iterator接口時指定了泛型爲String類型, 8 * 所以Scanner對象的Next方法,public String next(String pattern)返回數據類型就是String 9 * 10 * 第二種實現方法:接口使用什麼類型,實現類就使用什麼泛型,類跟着接口走 11 * 好比ArrayList類,其實現了List接口,能夠看到List接口泛型爲E,實現類的泛型也爲E,其下面的方法參數也相應變成E 12 * 13 */ 14 public interface GenericInterface<T> { 15 //定義一個簡單的抽象方法 16 public abstract void printArray(T t); 17 }
第一種方法實現接口中的泛型
1 package GenericTest; 2 3 /** 4 * 第一種實現方法:實現含有泛型的接口,接口實現時指定泛型類型 5 */ 6 public class GenericInterfaceImpl implements GenericInterface<String>{ 7 8 @Override 9 public void printArray(String s) { 10 System.out.println(s); 11 } 12 //能夠看到當接口指定泛型類型爲String後,方法參數也爲String了 13 }
第二種方法實現接口中的泛型
1 package GenericTest; 2 3 /** 4 * 第二種實現方法,接口定義了什麼泛型,實現類就是什麼泛型,以下所示實現類後面也要加<T> 5 */ 6 public class GenericInterfaceImpl1<T> implements GenericInterface<T>{ 7 8 @Override 9 public void printArray(T t) { 10 System.out.println(t); 11 } 12 //接口類型泛型爲T,實現類類型泛型也爲T 13 }
測試兩種實現
1 package GenericTest; 2 3 /** 4 * 測試類,測試接口中定義泛型 5 */ 6 public class GenericInterfaceImplTest { 7 8 public static void main(String[] args) { 9 //父類的接口指向子類的對象 10 //第一種實現方法 11 GenericInterface gi=new GenericInterfaceImpl(); 12 gi.printArray("hello my future"); 13 14 //第二種實現方法 15 GenericInterface gi1=new GenericInterfaceImpl1(); 16 gi1.printArray("hello my brother"); 17 gi1.printArray(8848); 18 gi.printArray("is a good phone,you deserve it"); 19 20 } 21 22 }
控制檯輸出結果,第一種實現其實限定了數據類型,如本例中爲String,第二種沒有限定。
通配符使用在方法中,當方法參數類型不肯定時,能夠使用"?"來代替類型,傳入的是什麼數據類型就是什麼類型,注意通配符不能用於建立對象。
package GenericTest; import java.util.ArrayList; import java.util.Iterator; /** * 泛型-通配符的使用,用 ?表示,其表明任意數據類型,只能做爲方法的參數使用,不能建立對象時使用 * */ public class GenericWildcardCharacter { public static void main(String[] args) { //建立兩個不一樣數據類型的集合,寫一個方法實現遍歷打印,寫方法時不知道須要打印的集合數據類型是什麼,所以使用通配符 //第一個集合 ArrayList<String> col1=new ArrayList<String>(); col1.add("you"); col1.add("are"); col1.add("beautiful"); //第二個集合 ArrayList<Integer> col2=new ArrayList<Integer>(); col2.add(8848); col2.add(618); col2.add(1111); //一個方法實現上面兩種數據類型集合的遍歷打印 printArray(col1); printArray(col2); //通配符不能用來建立對象 /*ArrayList<?> col3=new ArrayList<?>();*/ } //統配符做爲參數在方法中 public static void printArray(ArrayList<?> array){ Iterator<?> it=array.iterator(); while(it.hasNext()){ Object o=it.next();//返回數據類型不肯定,使用Object來接收 System.out.println(o); } } }
控制檯輸出狀況
另外通配符還有一個高級的應用,就是通配符的上下限。
1 package GenericTest; 2 3 import java.util.ArrayList; 4 import java.util.Collection; 5 6 /** 7 * 泛型-通配符高級使用,受限泛型 8 * 泛型的上限限定:? extends E 表明泛類型只能是E類型的子類 9 * 泛型的下限限定:? super E 表明泛類型只能是E類型的父類 10 */ 11 public class GenericWildcardCharacter1 { 12 13 public static void main(String[] args) { 14 //建立一些集合,其中Integer是Number的子類,Number是Object的子類,String是Object的子類 15 Collection<Integer> col1=new ArrayList<Integer>(); 16 Collection<String> col2=new ArrayList<String>(); 17 Collection<Number> col3=new ArrayList<Number>(); 18 Collection<Object> col4=new ArrayList<Object>(); 19 20 //調用使用了受限泛型統配符的方法 21 method1(col1); 22 /*method1(col2);//編譯失敗*/ 23 method1(col3); 24 /*method1(col4);//編譯失敗*/ 25 26 /*method2(col1);//編譯失敗*/ 27 /*method2(col2);//編譯失敗*/ 28 method2(col3); 29 method2(col4); 30 } 31 //上限限定 32 public static void method1(Collection<? extends Number> col){}; 33 //下限限定 34 public static void method2(Collection<? super Number> col){}; 35 }
泛型主要在集合中有普遍使用,能夠定義在類、方法和接口中,主要是不知道傳入的參數類型是什麼才使用了泛型來解決問題。