日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關咨詢
選擇下列產(chǎn)品馬上在線溝通
服務時間:8:30-17:00
你可能遇到了下面的問題
關閉右側工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
看完后讓你成為武松,手把手教你打死Java中的紙老虎

泛型,其實算是Java當中比較難的語法了,很多人一開始都對其一知半解,也很害怕閱讀帶泛型的源碼,雖然看起來語法很難,但當你理解后會覺得很簡單,其實只是一個紙老虎罷了。下面,我將會用非常簡單易懂的方式帶你去理解它,相信你在認真看完后會有非常大的收獲,從此不會再畏懼它!

[[422931]]

一. 泛型的定義

這里大家可以不必去看網(wǎng)上的有些定義,因為相對于比較學術化,只需記住泛型可以在程序設計中指定某種類型,讓程序的設計更加規(guī)范化即可

二. 為什么要用到泛型

了解到了泛型是什么后,那我們來討論討論為什么要用泛型這個語法,這個語法到底是干什么的?別急,下面,我先給大家舉一個例子: 

 
 
 
 
  1. class Stack { 
  2.     public Object[] objects; 
  3.     public int top; 
  4.  
  5.     public Stack() { 
  6.         this.objects =new Object[10]; 
  7.     } 
  8.  
  9.     public void push(Object obj) { 
  10.         objects[this.top++] = obj; 
  11.     } 
  12.  
  13.     public Object get() { 
  14.         return objects[this.top-1]; 
  15.     } 

大家可以看看這是在干什么呢?這是我們自己寫了一個棧,然后將棧里的數(shù)組類型設置成Object類型,這樣的話這個棧里任意類型的數(shù)據(jù)都可以存放了(Object類是任何類的父類,不管插入什么類型的數(shù)據(jù),都可以發(fā)生向上轉型)

下面,我們來測試一下: 

 
 
 
 
  1. public class Test { 
  2.     public static void main(String[] args) { 
  3.         Stack stack=new Stack(); 
  4.         stack.push(1); 
  5.         stack.push(2); 
  6.         stack.push("123"); 
  7.         String str=(String)stack.get(); 
  8.     } 

可以看到,我們可以向自己寫的棧里放入整形以及字符串等等任何類型的數(shù)據(jù),但注意一下取出數(shù)據(jù)的時候要進行強制類型轉換

以上這樣寫,可以向棧里存放任何類型的數(shù)據(jù),比較通用,其優(yōu)點也可以變成缺點,正因為太通用了,使代碼的規(guī)范性降低,看起來比較凌亂,這時候,我們可以考慮使用泛型,這樣可以在類中或者Java集合中存放特定的數(shù)據(jù)(使用Java集合時,一般都要用到泛型,而自定義的類型中可以使用泛型也可以不使用)

三. 泛型的寫法

以自定義的類型為例,寫法為在類名后面加上尖括號,里面寫上一個字母(注意,此處寫任何字母都可以,只起到一個標記這個類為泛型類的作用)

 
 
 
 
  1. class Stack 

而在new對象時,以棧里只能存放整形為例,前面的尖括號必須寫基本數(shù)據(jù)類型對應的包裝類,而后面的尖括號可以不用寫,示例如下:

 
 
 
 
  1. Stack stack = new Stack<>(); 

補一下Java中的基本數(shù)據(jù)類型與對應的包裝類:

因此,我們前面寫的自定義的棧可以寫成以下形式(以存放整形為例): 

 
 
 
 
  1. class Stack { 
  2.     public T[] objects; 
  3.     public int top; 
  4.  
  5.     public Stack() { 
  6.         this.objects = (T[])new Object[10]; 
  7.     } 
  8.  
  9.     public void push(T obj) { 
  10.         objects[this.top++] = obj; 
  11.     } 
  12.  
  13.     public T get() { 
  14.         return objects[this.top-1]; 
  15.     } 
  16.  Stack stack = new Stack<>(); 
  17.         stack.push(1); 
  18.         stack.push(2); 
  19.         int ret = stack.get(); 
  20.         System.out.println(ret); 

特別注意此處:public Stack() { this.objects = (T[])new Object[10]; }

這里不能寫成this.objects=new T[10];

原因:

  1. 不能new泛型類型的數(shù)組
  2. 也可理解為泛型是先檢查后編譯的,如果new泛型類型的數(shù)組的話,編譯器檢查時并不知道T是什么類型的,因此會報錯。而編譯的時候才會進行擦除機制,都會將其轉換為Object類型
  3. 正因為有這個擦除機制,這里才能進行數(shù)組整體強制類型轉換(一般數(shù)組不能整體進行強制類型轉換),因為泛型只是在編譯的時候起作用,而實際運行時都會被擦除成Object類型,即實際運行時是沒有泛型這個概念的,也即實際運行時類型都是一樣的,所以T本質上是object類型的,所以此代碼等價于不進行強制類型轉換!!!
  4. 而直接指定泛型的代碼(不是T) 比如:Stack和Stack都是在運行時直接把尖括號里的類型擦掉了,可以看到直接打印的結果(并沒有打印出類型):

此處注意多理解理解

四. 泛型的使用實例

1. 求最大值

以上就是泛型的一個重要知識點了,但光看是不夠的,還是得通過例子讓大家有一個更為深入的理解,比如,如何寫一個泛型類來求數(shù)組的最大值呢?

基本的框架大概是這樣的:(沒看懂的小可愛好好看看上面講的內容哦) 

 
 
 
 
  1. class Algorithm> { 
  2.     public T findMax(T[] array) { 
  3.         T max = array[0]; 
  4.         for (int i = 1; i < array.length; i++) { 
  5.             if(max < array[i]) { 
  6.                 max = array[i]; 
  7.             } 
  8.         } 
  9.         return max; 
  10.     } 

但是此代碼if(max < array[i])會報錯,為什么呢?因為將來給T傳的值一定是一個引用類型,引用類型不能直接比較大于或者小于的,是要用Comparable或Comparator接口里的方法比較的,因為泛型在編譯的時候會被擦除成Object類型,但Object類本身并沒有實現(xiàn)Comparable或Comparator接口,所以我們要控制其不要擦除到Object類,所以要給泛型指定一個邊界

具體寫法如下: 

 
 
 
 
  1. class Algorithm> { 
  2.     public T findMax(T[] array) { 
  3.         T max = array[0]; 
  4.         for (int i = 1; i < array.length; i++) { 
  5.             //max < array[i] 
  6.             if(max.compareTo(array[i]) < 0) { 
  7.                 max = array[i]; 
  8.             } 
  9.         } 
  10.         return max; 
  11.     } 
  12.  
  13. class Algorithm

注意,extends叫做上界,此代碼代表的意思為T這個泛型類會擦除到實現(xiàn)了Comparable接口的地方,換句話說,這個T類型一定是實現(xiàn)了Comparable接口的

同理:這個代碼public class MyArrayList { ... }代表E為Number的子類或Number本身

下面讓我們來用一下: 

 
 
 
 
  1. Algorithm algorithm1 = new Algorithm<>(); 
  2.        Integer[] integers = {1,2,13,4,5}; 
  3.        Integer ret = algorithm1.findMax(integers); 
  4.        System.out.println(ret); 

運行結果如下:

[[422934]]

成功了!

2. 優(yōu)化

經(jīng)過上面的努力,我們已經(jīng)寫出了一個泛型類來求一個數(shù)組的最大值了,但是,上面的例子是一個整形數(shù)組,那么我們能不能在數(shù)組里存放別的類型去比較呢?答案是可以的,但是我們還得去new一個對象,例如:Algorithm algorithm2 = new Algorithm<>();這樣很麻煩。但是我們可以將求最大值的方法設置成靜態(tài)的class Algorithm2 ,因為是靜態(tài)的方法,不需要new對象,所以就沒有在new對象時指定泛型的過程了,所以沒必要給方法后加尖括號,但是去掉之后,代碼又會被錯:

我們可以這樣修改: 

 
 
 
 
  1. class Algorithm2 { 
  2.     public static> T findMax(T[] array) { 
  3.         T max = array[0]; 
  4.         for (int i = 1; i < array.length; i++) { 
  5.             if(max.compareTo(array[i]) < 0) { 
  6.                 max = array[i]; 
  7.             } 
  8.         } 
  9.         return max; 
  10.     } 

此方法public static> T findMax(T[] array){}叫做泛型方法

下面繼續(xù)帶大家來用一下: 

 
 
 
 
  1. public static void main(String[] args) { 
  2.         Integer[] integers = {1,2,13,4,5}; 
  3.         //會根據(jù)形參的類型推導出整個泛型的類型參數(shù) 
  4.         Integer ret = Algorithm2.findMax(integers); 
  5.         System.out.println(ret); 
  6.         Integer ret2 = Algorithm2.findMax(integers); 
  7.         System.out.println(ret2); 
  8.     } 

注意,ret1寫法和ret2寫法是一樣的,都可以

打印結果如下:

五. 通配符

1. 基本寫法

通配符也是泛型的一種,下面我們來寫一個泛型方法來打印集合中的元素。 

 
 
 
 
  1. class Test { 
  2.  
  3.     public static void print(ArrayList list) { 
  4.  
  5.         for (T t : list) { 
  6.             System.out.println(t); 
  7.         } 
  8.     } 

這個寫法很簡單,上文都講過了,那么讓我們來試著用一下吧: 

 
 
 
 
  1. public static void main(String[] args) { 
  2.         ArrayList list = new ArrayList<>(); 
  3.         list.add(1); 
  4.         list.add(2); 
  5.         list.add(3); 
  6.         Test.print(list); 
  7.     } 

打印的結果如下:

除了以上這種寫法,我們還可以將其改成通配符的寫法,先給大家上代碼: 

 
 
 
 
  1. //?代表通配符  擦除機制  Object 
  2.     public static void print2(ArrayList list) { 
  3.         for (Object t : list) { 
  4.             System.out.println(t); 
  5.         } 
  6.     } 

此處for (Object t : list)必須這樣寫,因為通配符也是有擦除機制的,會在編譯器編程Object類型。

2. 上界

  • 語法:
  • 示例: 
 
 
 
 
  1. public static void printAll(MyArrayList list) {  
  2. ...  
  3.  
  4. xxxxxxxxxxbr public static void printAll(MyArrayList list) {br...br } 

代表可以傳入類型實參是 Number 子類的任意類型的 MyArrayList所以以下調用都是正確的: 

 
 
 
 
  1. printAll(new MyArrayList());  
  2. printAll(new MyArrayList());  
  3. printAll(new MyArrayList()); 
  4.  
  5. xxxxxxxxxxbr printAll(new MyArrayList());brprintAll(new MyArrayList());brprintAll(new MyArrayList()); 

以下調用都是錯誤的: 

 
 
 
 
  1. printAll(new MyArrayList());  
  2. printAll(new MyArrayList ()); 
  3.  
  4. xxxxxxxxxxbr printAll(new MyArrayList());brprintAll(new MyArrayList()); 

3. 下界

下界和上界的用法很類似

  • 語法:
  • 示例: 
 
 
 
 
  1. public static void printAll(MyArrayList list) {  
  2. ...  
  3.  
  4. xxxxxxxxxxbr public static void printAll(MyArrayList list) {br...br} 

代表可以傳入類型實參是 Integer 父類的任意類型的 MyArrayList所以以下調用是正確的: 

 
 
 
 
  1. printAll(new MyArrayList());  
  2. printAll(new MyArrayList());  
  3. printAll(new MyArrayList()); 
  4.  
  5. xxxxxxxxxxbr printAll(new MyArrayList());brprintAll(new MyArrayList());brprintAll(new MyArrayList()); 

以下調用是錯誤的: 

 
 
 
 
  1. printAll(new MyArrayList());  
  2. printAll(new MyArrayList()); 
  3.  
  4. xxxxxxxxxxbr printAll(new MyArrayList());brprintAll(new MyArrayList()); 

六. 泛型的限制 

學習完后,我們應該注意泛型使用過程中以下一些限制:

  • 泛型類型參數(shù)不支持基本數(shù)據(jù)類型

  • 無法實例化泛型類型的對象

  • 無法使用泛型類型聲明靜態(tài)的屬性

  • 無法使用 instanceof 判斷帶類型參數(shù)的泛型類型(因為被擦除機制擦除了)

  • 無法創(chuàng)建泛型類數(shù)組

  • 無法 create、catch、throw 一個泛型類異常(異常不支持泛型)

  • 泛型類型不是形參一部分,無法重載

好啦,本次泛型知識點的分享就先告一段落了,整理不易,但如果能幫到大家很開心了。也希望大家多理解理解,不論是剛開始學習還是復習,都值得仔細揣摩哦!一起加油吧!

 

 


當前名稱:看完后讓你成為武松,手把手教你打死Java中的紙老虎
標題鏈接:http://m.5511xx.com/article/dhpehop.html