------- android培訓、java培訓、期待與您交流! ----------
所謂泛型就是允許在定義類、接口時指定類型形參,這個類型形參將在聲明變量、創建對象時確定。增加了泛型支持后的集合,完全可以記住集合中元素的類型,並可以在編譯時檢查集合中元素的類型。即解決一些安全問題;同時還可以讓代碼變得更加簡潔。
一.使用泛型
泛型的格式:通過<>來定義要操作的引用數據類型。
1 public class GenericDemo { 2 public static void main(String[] args) 3 { 4 // 創建一個只能保存字符串的List 集合 5 List<String> strList = new ArrayList<String>() ; 6 strList.add("Generic") ; 7 // 如果存放其他對象這回出現編譯錯誤。 8 System.out.println(strList); 9 } 10 }
使用泛型的好處:
1、將運行時期出現的ClassCastExcpetion , 轉移到了編譯時期。方便於程序員解決問題,讓運行時期問題減少。
2、避免了強制轉換的麻煩。
如下代碼:
1 class StringDemo 2 { 3 String name ; 4 public StringDemo(String name ) 5 { 6 this.name = name ; 7 } 8 } 9 public class GenericDemo { 10 public static void main(String[] args) 11 { 12 List list = new ArrayList() ; 13 list.add(new StringDemo("煩煩煩煩煩01")) ; 14 list.add(new StringDemo("煩煩煩煩煩02")) ; 15 list.add(new StringDemo("煩煩煩煩煩03")) ; 16 list.add(new StringDemo("煩煩煩煩煩04")) ; 17 18 list.add(1000) ; 19 MyIterator(list) ; 20 } 21 // 定義遍歷方法: 22 public static void MyIterator(List list) 23 { 24 Iterator it = list.iterator() ; 25 while (it.hasNext() ) 26 { 27 StringDemo s = (StringDemo) it.next() ; 28 System.out.println(s.name); 29 } 30 } 31 }
}
在調用MyIterator(List list) 方法時會發生ClassCastException 異常。而且在編譯時是不會有任何提示,只有運行時會出現,所以使的程序存在安全隱患。
如果使用泛型則會在編譯時提示錯誤,而且在遍歷時不需要強制轉換。如:
1 class StringDemo 2 { 3 String name ; 4 public StringDemo(String name ) 5 { 6 this.name = name ; 7 } 8 } 9 public class GenericDemo { 10 public static void main(String[] args) 11 { 12 List<StringDemo> list = new ArrayList<StringDemo>() ; 13 list.add(new StringDemo("煩煩煩煩煩01")) ; 14 list.add(new StringDemo("煩煩煩煩煩02")) ; 15 list.add(new StringDemo("煩煩煩煩煩03")) ; 16 list.add(new StringDemo("煩煩煩煩煩04")) ; 17 18 // 下面一行代碼在編譯時會出錯: 19 list.add(1000) ; 20 MyIterator(list) ; 21 } 22 // 定義遍歷方法: 23 public static void MyIterator(List list) 24 { 25 Iterator<StringDemo> it = list.iterator() ; 26 while (it.hasNext() ) 27 { 28 System.out.println( it.next().name); 29 } 30 } 31 }
注意:在使用Java提供的對象時,什么時候寫泛型呢?
只要見到<> (<>就是用來接收類型的。),就要定義泛型。當使用集合時,將集合中要存儲的數據類型作為參數傳遞到<>中即可。
二.了解泛型
ArrayList<E> 類定義和ArrayList<Integer> 類引用中涉及的術語:
> 整個稱為ArrayList<E> 泛型類型。
> ArrayList<E> 中的E稱為類型變量或類型參數。
> 整個ArrayList<Integer> 稱為參數化的類型。
> ArrayList<Integer> 中的Integer 稱為類型參數的實例或實際類型參數。
> ArrayList<Integer> 中的<> 念着typeof
> ArrayList 稱為原始類型
參數化類型不考慮類型參數的繼承:
> Vector<String> v = new Vector<Object>() ; //錯誤
> Vector<Object> v = new Vector<String>() ; //也錯誤
創建數組實例時,數組的元素不能使用參數化的類型:
> Vector<Integer> vectorList[] = new Vector<Integer>[10] ; //錯誤
三.定義泛型類
除了Java提供了一些類增加了泛型支持外,我們可以定義泛型支持的類。那么在什么時候定義泛型類呢?
當類中操作的引用數據類型不確定時可以定義泛型類。
格式如下:
class Tools<T> { }
具體操作:
1 //定義一個工具類Tools 2 //因為不知道要操作的類型是什么所增加泛型支持 3 class Tools<T> 4 { 5 // 包含輸出函數: 6 public void sop(T t) 7 { 8 System.out.println("sop:"+t); 9 } 10 } 11 //定義一個Books 類 12 class Books 13 { 14 private String name ; 15 public Books(String name) 16 { 17 this.name = name ; 18 } 19 // 重寫toString 方法 20 public String toString() 21 { 22 return "name = " + name ; 23 } 24 } 25 public class GenericText 26 { 27 public static void main(String[] args) 28 { 29 // 創建一個Tools 實例tool ,定義 tool 要操作的數據類型為Books 30 Tools<Books> tool = new Tools<Books>() ; 31 // tool 可以操作 Books 類型,還可以操作Integer 類型和String類型。 32 tool.sop(new Books("誅仙")); 33 } 34 }
定義一個Tools 類 用來完成打印操作,但是應為不知道要操作的數據類型是什么,所以可以定義成泛型類。
三.泛型方法
泛型類定義的泛型,在整個類中有效,如果被方法使用,那么泛型類的對象明確要操作的具體類型后,所有要操作的類型就已經固定了。為了讓不同方法可以操作不同類型,而且類型還不確定,
那么可以將泛型定義在方法上。
定義泛型方法格式如下:
public <T> void show(T t) 注意:<>放在修飾符后面,返回值前面 { }
具體操作如下:
1 //定義一個工具類Tools 2 //因為不知道要操作的類型是什么所增加泛型支持 3 class Tools<T> 4 { 5 // 包含輸出函數: 6 public void sop(T t) 7 { 8 System.out.println("sop:"+t); 9 } 10 // 定義的泛型方法: 11 public <T> void show (T t) 12 { 13 System.out.println("show:"+t); 14 } 15 } 16 //定義一個Books 類 17 class Books 18 { 19 private String name ; 20 public Books(String name) 21 { 22 this.name = name ; 23 } 24 // 重寫toString 方法 25 public String toString() 26 { 27 return "name = " + name ; 28 } 29 } 30 public class GenericText 31 { 32 public static void main(String[] args) 33 { 34 // 創建一個Tools 實例tool ,定義 tool 要操作的數據類型為Books 35 Tools<Books> tool = new Tools<Books>() ; 36 // tool 可以操作 Books 類型,還可以操作Integer 類型和String類型。 37 tool.sop(new Books("誅仙")); 38 tool.show(new Books("誅仙")) ; 39 // 下面的方法編譯時會報錯》、: 40 tool.sop(1000) ; 41 tool.sop("String") ; 42 43 // 但下面卻不會報錯,並且正常運行。 44 tool.show(1000) ; 45 tool.show("String") ; 46 } 47 }
通過上面的代碼,可以知道泛型類和泛型方法可以同時定義,且不沖突。但是也有特殊情況:靜態方法不可以訪問定義類上的泛型,如:
class Tools<T> { public static void method(T t) { } } 上面的書寫是錯誤的,
如果靜態方法操作的引用數據類型不確定,可將泛型定義在方法上:
class Tools<T> { public static <T> void method(T t) { } }
四.泛型限定和通配符
4.1 通配符
類型通配符是一個問號(?):問號作為類型實參傳給List 集合寫作:List<?>。
1 //定義一個Books 類 2 class Books 3 { 4 private String name ; 5 public Books(String name) 6 { 7 this.name = name ; 8 } 9 // 重寫toString 方法 10 public String toString() 11 { 12 return "name = " + name ; 13 } 14 } 15 public class GenericText 16 { 17 public static void main(String[] args) 18 { 19 // 創建一個只能存儲 Books 類型元素的 List 集合。 20 List<Books> bookList = new ArrayList<Books>() ; 21 bookList.add(new Books("誅仙")) ; 22 bookList.add(new Books("笑傲江湖")) ; 23 24 // 創建一個只能存儲String 類型元素的List 集合 25 List<String> strList = new ArrayList<String>() ; 26 strList.add("Generic001") ; 27 strList.add("Generic002") ; 28 29 MyIterator(strList) ; 30 MyIterator(bookList) ; 31 32 } 33 // 定義個遍歷List 集合的方法。 34 public static void MyIterator(List<?> strList) 35 { 36 Iterator<?> it = strList.iterator() ; 37 while(it.hasNext()) 38 { 39 System.out.println(it.next()); 40 } 41 } 42 }
在 MyIterator 方法中使用了類型通配符 ? ,好處是只寫一個 遍歷方法便可操作List 集合的遍歷,缺點是不能調用元素中的特定方法。
4.2 泛型限定:
1、 ? extends E : 可以接收E類型或者E的子類型。上限定。
2、? super E : 可以接收E類型或者E的父類型。下限定。
1 class Books 2 { 3 String name ; 4 public Books(String name) 5 { 6 this.name = name ; 7 } 8 public String toString() 9 { 10 return "name:" + name ; 11 } 12 } 13 class ComicBooks extends Books 14 { 15 public ComicBooks(String name) { 16 super(name); 17 } 18 } 19 class Person_1 20 { 21 String name ; 22 public Person_1 (String name) 23 { 24 this.name = name ; 25 } 26 } 27 public class GenericTreeSet { 28 29 public static void main(String[] args) 30 { 31 // 定義 TreeSet 集合 ,並且里面只存儲ComicBooks類型元素,切按照自已的比較規則排序 32 TreeSet<ComicBooks> bookTree = new TreeSet<ComicBooks>(new MyComparable()) ; 33 34 bookTree.add(new ComicBooks("aaaaaa")) ; 35 bookTree.add(new ComicBooks("aaa3gfaaa")) ; 36 bookTree.add(new ComicBooks("afdfef")) ; 37 bookTree.add(new ComicBooks("asdffefq")) ; 38 // 調用 39 MyIterator(bookTree) ; 40 41 // 下面代碼編譯會出現異常 42 TreeSet<Person_1> p = new TreeSet<Person_1>(new MyComparable()) ; 43 } 44 // 定義遍歷方法:只能操作Books 類型或者 Books的子類型 45 public static void MyIterator(TreeSet<? extends Books> bookTree) 46 { 47 Iterator<? extends Books> it = bookTree.iterator() ; 48 while(it.hasNext()) 49 { 50 System.out.println(it.next().toString()); 51 } 52 } 53 } 54 //定義比較器 :按倒序排序且該比較器只適用於 Books 類型或者 Books的子類型 55 class MyComparable implements Comparator<Books> 56 { 57 public int compare(Books o1 , Books o2) 58 { 59 return o2.name.compareTo(o1.name); 60 } 61 }
所以,當我們定義的某些方法只作用與某些類與其子類時,可以通過泛型限定來實現。