黑馬程序員-JAVA基礎-Java 集合之泛型


------- 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 }

  所以,當我們定義的某些方法只作用與某些類與其子類時,可以通過泛型限定來實現。

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM