成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

關于Java泛型這些事

開發(fā) 后端
泛型(generics)是 JDK 5 中引入的一個新特性, 泛型提供了編譯時類型安全檢測機制,該機制允許程序員在編譯時檢測到非法的類型。

[[443125]]

關于泛型,有一道經(jīng)典的考題:

  1. public static void main(String[] args) { 
  2.         List<String> list1= new ArrayList<String>(); 
  3.         List<Integer> list2= new ArrayList<Integer>(); 
  4.         System.out.println(list1.getClass() == list2.getClass()); 
  5.     } 

請問上面代碼的輸出結果是什么?

如果是了解泛型的同學會很容易答出:true,如果是不了解泛型的同學則很可能會答錯。今天就和大家一起來重溫一下Java泛型相關的知識。

一、什么是泛型?

泛型(generics)是 JDK 5 中引入的一個新特性, 泛型提供了編譯時類型安全檢測機制,該機制允許程序員在編譯時檢測到非法的類型。泛型的本質(zhì)是參數(shù)化類型,也就是說所操作的數(shù)據(jù)類型被指定為一個參數(shù)。具有以下特點:

  • 與普通的 Object 代替一切類型這樣簡單粗暴而言,泛型使得數(shù)據(jù)的類別可以像參數(shù)一樣由外部傳遞進來。它提供了一種擴展能力。它更符合面向抽象開發(fā)的軟件編程宗旨。
  • 當具體的類型確定后,泛型又提供了一種類型檢測的機制,只有相匹配的數(shù)據(jù)才能正常的賦值,否則編譯器就不通過。所以說,它是一種類型安全檢測機制,一定程度上提高了軟件的安全性防止出現(xiàn)低級的失誤。
  • 泛型提高了程序代碼的可讀性,不必要等到運行的時候才去強制轉(zhuǎn)換,在定義或者實例化階段,因為 Cache這個類型顯化的效果,程序員能夠一目了然猜測出代碼要操作的數(shù)據(jù)類型。

泛型按照使用情況可以分為3種:泛型類、泛型方法、泛型接口。

1.泛型類

我們可以定義如下一個泛型類

  1. /** 
  2.  * @author machongjia 
  3.  * @date 2021/12/28 20:02 
  4.  * @description 
  5.  */ 
  6. public class Generic<T> { 
  7.  
  8.     private T var; 
  9.  
  10.     public Generic(T var) { 
  11.         this.var = var; 
  12.     } 
  13.  
  14.     public T getVar() { 
  15.         return var; 
  16.     } 
  17.  
  18.     public static void main(String[] args) { 
  19.         Generic<Integer> i = new Generic<Integer>(1000); 
  20.         Generic<String> s = new Generic<String>("hello"); 
  21.         System.out.println(i.getVar()); 
  22.         System.out.println(s.getVar()); 
  23.     } 

輸出結果:

  1. 1000 
  2. hello 

常用的類似于T這樣的類型參數(shù)包括:

T:代表一般的任何類

E:代表 Element 的意思,或者 Exception 異常的意思

K:代表 Key 的意思。

V:代表 Value 的意思,通常與 K 一起配合使用

S:代表 Subtype 的意思

泛型類可以不止接受一個參數(shù)T,還可以接受多個參數(shù),類似于下面這種:

  1. public class Generic<E,T> { 
  2.  
  3.     private E var1; 
  4.     private T var2; 
  5.  
  6.     public Generic(E var1, T var2) { 
  7.         this.var1 = var1; 
  8.         this.var2 = var2; 
  9.     } 
  10.  
  11.     public static void main(String[] args) { 
  12.         Generic<Integer,String> generic = new Generic<Integer,String>(1000,"hello"); 
  13.         System.out.println(generic.var1); 
  14.         System.out.println(generic.var2); 
  15.     } 

2.泛型方法

  1. public class Generic { 
  2.  
  3.     public <T> void testMethod(T t){ 
  4.  
  5.     } 
  6.  

泛型方法與泛型類稍有不同的地方是,類型參數(shù)也就是尖括號那一部分是寫在返回值前面的。中的 T 被稱為類型參數(shù),而方法中的 T 被稱為參數(shù)化類型,它不是運行時真正的參數(shù)。

當然,聲明的類型參數(shù),其實也是可以當作返回值的類型的。

泛型類與泛型方法共存的情況:

  1. public class Generic<T> { 
  2.  
  3.     public void testMethod(T t){ 
  4.         System.out.println(t.getClass().getName()); 
  5.     } 
  6.  
  7.     public <T> T testMethod1(T t){ 
  8.         return t; 
  9.     } 

上面代碼中,Test1是泛型類,testMethod 是泛型類中的普通方法,而 testMethod1 是一個泛型方法。而泛型類中的類型參數(shù)與泛型方法中的類型參數(shù)是沒有相應的聯(lián)系的,泛型方法始終以自己定義的類型參數(shù)為準。

3.泛型接口

泛型接口與泛型類的定義及使用基本相同。泛型接口常被用在各種類的生產(chǎn)器中,可以看一個例子:

  1. //定義一個泛型接口 
  2. public interface Generator<T> { 
  3.     public T next(); 

當實現(xiàn)泛型接口的類,未傳入泛型實參時:

  1. /** 
  2.  * 未傳入泛型實參時,與泛型類的定義相同,在聲明類的時候,需將泛型的聲明也一起加到類中 
  3.  * 即:class FruitGenerator<T> implements Generator<T>{ 
  4.  * 如果不聲明泛型,如:class FruitGenerator implements Generator<T>,編譯器會報錯:"Unknown class" 
  5.  */ 
  6. class FruitGenerator<T> implements Generator<T>{ 
  7.     @Override 
  8.     public T next() { 
  9.         return null
  10.     } 

當實現(xiàn)泛型接口的類,傳入泛型實參時:

  1. /** 
  2.  * 傳入泛型實參時,定義一個生產(chǎn)器實現(xiàn)這個接口,雖然我們只創(chuàng)建了一個泛型接口Generator<T> 
  3.  * 但是我們可以為T傳入無數(shù)個實參,形成無數(shù)種類型的Generator接口。 
  4.  * 在實現(xiàn)類實現(xiàn)泛型接口時,如已將泛型類型傳入實參類型,則所有使用泛型的地方都要替換成傳入的實參類型 
  5.  * 即:Generator<T>,public T next();中的的T都要替換成傳入的String類型。 
  6.  */ 
  7. public class FruitGenerator implements Generator<String> { 
  8.  
  9.     private String[] fruits = new String[]{"Apple""Banana""Pear"}; 
  10.  
  11.     @Override 
  12.     public String next() { 
  13.         Random rand = new Random(); 
  14.         return fruits[rand.nextInt(3)]; 
  15.     } 

4.通配符?

通配符的出現(xiàn)是為了指定泛型中的類型范圍,包含以下3 種形式。

  • <?>被稱作無限定的通配符。
  • <? extends T>被稱作有上限的通配符。
  • <? super T>被稱作有下限的通配符。

無限定通配符<?>

無限定通配符經(jīng)常與容器類配合使用,它其中的 ? 其實代表的是未知類型,所以涉及到 ? 時的操作,一定與具體類型無關。

  1. public void testWildCards(Collection<?> collection){ 

上面的代碼中,方法內(nèi)的參數(shù)是被無限定通配符修飾的 Collection 對象,它隱略地表達了一個意圖或者可以說是限定,那就是 testWidlCards() 這個方法內(nèi)部無需關注 Collection 中的真實類型,因為它是未知的。所以,你只能調(diào)用 Collection 中與類型無關的方法。

相對應,前者?代表類型T及T的子類,后者?代表T及T的超類。

值得注意的是,如果用泛型方法來取代通配符,那么上面代碼中 collection 是能夠進行寫操作的。只不過要進行強制轉(zhuǎn)換。

二、什么是泛型的類型擦除?

Java泛型這個特性是從JDK 1.5才開始加入的,因此為了兼容之前的版本,Java泛型的實現(xiàn)采取了“偽泛型”的策略,即Java在語法上支持泛型,但是在編譯階段會進行所謂的“類型擦除”(Type Erasure),將所有的泛型表示(尖括號中的內(nèi)容)都替換為具體的類型(其對應的原生態(tài)類型),就像完全沒有泛型一樣。理解類型擦除對于用好泛型是很有幫助的,尤其是一些看起來“疑難雜癥”的問題,弄明白了類型擦除也就迎刃而解了。

  • 泛型的類型擦除原則是:
  • 消除類型參數(shù)聲明,即刪除<>及其包圍的部分。
  • 根據(jù)類型參數(shù)的上下界推斷并替換所有的類型參數(shù)為原生態(tài)類型:如果類型參數(shù)是無限制通配符或沒有上下界限定則替換為Object,如果存在上下界限定則根據(jù)子類替換原則取類型參數(shù)的最左邊限定類型(即父類)。
  • 為了保證類型安全,必要時插入強制類型轉(zhuǎn)換代碼。
  • 自動產(chǎn)生“橋接方法”以保證擦除類型后的代碼仍然具有泛型的“多態(tài)性”。

1.類型擦除做了什么?

上面我們說了,編譯完成后會對泛型進行類型擦除,如果想要眼見為實,實際看一下的話應該怎么辦呢?那么就需要對編譯后的字節(jié)碼文件進行反編譯了,這里使用一個輕量級的小工具Jad來進行反編譯,Jad的使用也很簡單,下載解壓后,把需要反編譯的字節(jié)碼文件放在目錄下,然后在命令行里執(zhí)行下面的命令就可以在同目錄下生成反編譯后的.java文件了:

  1. jad -sjava Test.class 

好了,工具準備好了,下面我們就看一下不同情況下的類型擦除。

無限制類型擦除

當類定義中的類型參數(shù)沒有任何限制時,在類型擦除后,會被直接替換為Object。在下面的例子中,中的類型參數(shù)T就全被替換為了Object(左側(cè)為編譯前的代碼,右側(cè)為通過字節(jié)碼文件反編譯得到的代碼):

有限制類型擦除 

當類定義中的類型參數(shù)存在限制時,在類型擦除中替換為類型參數(shù)的上界或者下界。下面的代碼中,經(jīng)過擦除后T被替換成了Integer:

擦除方法中的類型參數(shù)

比較下面兩邊的代碼,可以看到在擦除方法中的類型參數(shù)時,和擦除類定義中的類型參數(shù)一致,無限制時直接擦除為Object,有限制時則會被擦除為上界或下界:

2.類型擦除帶來了哪些局限性?

類型擦除,是泛型能夠與之前的 java 版本代碼兼容共存的原因。但也因為類型擦除,它會抹掉很多繼承相關的特性,這是它帶來的局限性。

理解類型擦除有利于我們繞過開發(fā)當中可能遇到的雷區(qū),同樣理解類型擦除也能讓我們繞過泛型本身的一些限制。比如

正常情況下,因為泛型的限制,編譯器不讓最后一行代碼編譯通過,因為類似不匹配,但是,基于對類型擦除的了解,利用反射,我們可以繞過這個限制。

  1. public interface List<E> extends Collection<E>{ 
  2.    
  3.    boolean add(E e); 

上面是 List 和其中的 add() 方法的源碼定義。

因為 E 代表任意的類型,所以類型擦除時,add 方法其實等同于:

  1. boolean add(Object obj); 

那么,利用反射,我們繞過編譯器去調(diào)用 add 方法。

  1. public class ToolTest { 
  2.  
  3.   public static void main(String[] args) { 
  4.     List<Integer> ls = new ArrayList<>(); 
  5.     ls.add(23); 
  6. //    ls.add("text"); 
  7.     try { 
  8.       Method method = ls.getClass().getDeclaredMethod("add",Object.class); 
  9.  
  10.       method.invoke(ls,"test"); 
  11.       method.invoke(ls,42.9f); 
  12.     } catch (NoSuchMethodException e) { 
  13.       // TODO Auto-generated catch block 
  14.       e.printStackTrace(); 
  15.     } catch (SecurityException e) { 
  16.       // TODO Auto-generated catch block 
  17.       e.printStackTrace(); 
  18.     } catch (IllegalAccessException e) { 
  19.       // TODO Auto-generated catch block 
  20.       e.printStackTrace(); 
  21.     } catch (IllegalArgumentException e) { 
  22.       // TODO Auto-generated catch block 
  23.       e.printStackTrace(); 
  24.     } catch (InvocationTargetException e) { 
  25.       // TODO Auto-generated catch block 
  26.       e.printStackTrace(); 
  27.     } 
  28.  
  29.     for ( Object o: ls){ 
  30.       System.out.println(o); 
  31.     } 
  32.   } 

打印結果是:

  1. 23 
  2. test 
  3. 42.9 

可以看到,利用類型擦除的原理,用反射的手段就繞過了正常開發(fā)中編譯器不允許的操作限制。

 

責任編輯:武曉燕 來源: 碼蟲甲
相關推薦

2021-07-29 09:20:18

Java泛型String

2017-03-07 11:45:57

DevOps容器

2017-04-10 15:11:16

2021-09-28 06:28:50

云原生安全云計算

2018-01-03 11:35:34

推送AndroidiOS

2024-04-23 08:23:36

TypeScript泛型Generics

2009-09-25 10:03:51

Java泛型

2022-07-12 06:17:43

GoogleGolang開發(fā)工作

2009-09-01 17:59:36

C#泛型的作用

2015-07-13 08:49:54

2017-10-12 10:20:13

服務器運行壽命

2011-06-03 08:49:54

Java

2021-06-17 06:51:32

Java泛型Java編程

2017-03-06 16:51:52

Java泛型實現(xiàn)

2020-10-20 10:17:20

Java泛型Type

2019-06-25 15:00:53

SpringNullJava

2021-09-29 18:17:30

Go泛型語言

2021-03-26 08:41:11

Go語言Docker

2021-07-01 06:47:30

Java泛型泛型擦除

2012-05-01 08:06:49

手機
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 一区二区免费 | 日本欧美视频 | 亚洲精品一区二区在线 | 美女一级a毛片免费观看97 | 一区二区在线不卡 | 99精品久久久 | 亚洲精品视频在线看 | 亚洲一区二区久久 | 亚洲香蕉在线视频 | 91麻豆精品一区二区三区 | 国产精品地址 | 欧美中文字幕一区 | av一区二区三区四区 | 91免费看片 | 日韩成人国产 | 荷兰欧美一级毛片 | 色资源在线 | 亚洲欧美精品在线观看 | 九九热在线观看 | 欧美精品一区二区三区四区五区 | 激情五月婷婷在线 | 日本在线黄色 | 国产精品精品久久久 | 久久中文字幕一区 | 国产精品观看 | www.xxxx欧美 | 国产成人精品一区二区三区视频 | 刘亦菲国产毛片bd | 亚洲精品国产电影 | 免费的黄色片子 | 日韩一二三区视频 | 久久久久久综合 | 久久国内| 国产精品18久久久久久白浆动漫 | 欧美精品久久久久久久久老牛影院 | 精品在线播放 | 久久伊人免费视频 | 亚洲欧洲激情 | 国产在线播 | h片在线播放| 日本三级电影在线看 |