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

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

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷(xiāo)解決方案
重溫Java泛型,帶你更深入地理解它,更好的使用它!

 1. 引言

創(chuàng)新互聯(lián)公司服務(wù)項(xiàng)目包括仙居網(wǎng)站建設(shè)、仙居網(wǎng)站制作、仙居網(wǎng)頁(yè)制作以及仙居網(wǎng)絡(luò)營(yíng)銷(xiāo)策劃等。多年來(lái),我們專(zhuān)注于互聯(lián)網(wǎng)行業(yè),利用自身積累的技術(shù)優(yōu)勢(shì)、行業(yè)經(jīng)驗(yàn)、深度合作伙伴關(guān)系等,向廣大中小型企業(yè)、政府機(jī)構(gòu)等提供互聯(lián)網(wǎng)行業(yè)的解決方案,仙居網(wǎng)站推廣取得了明顯的社會(huì)效益與經(jīng)濟(jì)效益。目前,我們服務(wù)的客戶(hù)以成都為中心已經(jīng)輻射到仙居省份的部分城市,未來(lái)相信會(huì)繼續(xù)擴(kuò)大服務(wù)區(qū)域并繼續(xù)獲得客戶(hù)的支持與信任!

jdk5.0中引入了Java泛型,目的是減少錯(cuò)誤,并在類(lèi)型上添加額外的抽象層。本文將簡(jiǎn)要介紹Java中的泛型、泛型背后的目標(biāo)以及如何使用泛型來(lái)提高代碼的質(zhì)量。

2. 為什么要用泛型?

設(shè)想一個(gè)場(chǎng)景,我們希望用Java創(chuàng)建一個(gè)列表來(lái)存儲(chǔ)Integer;代碼可能會(huì)寫(xiě)成這樣:

 
 
 
 
  1. List list = new LinkedList(); 
  2. list.add(new Integer(1));  
  3. Integer i = list.iterator().next(); 

令人驚訝的是,編譯器會(huì)提示最后一行。它不知道返回的數(shù)據(jù)類(lèi)型是什么。因此,編譯器提示需要進(jìn)行顯式轉(zhuǎn)換:

 
 
 
 
  1. Integer i = (Integer) list.iterator.next(); 

沒(méi)有任何約定可以保證列表的返回類(lèi)型是整數(shù)。定義的列表可以包含任何對(duì)象。我們只知道我們是通過(guò)檢查上下文來(lái)檢索列表的。在查看類(lèi)型時(shí),它只能保證它是一個(gè)Object,因此需要顯式轉(zhuǎn)換來(lái)確保類(lèi)型是安全的。

這種轉(zhuǎn)換可能會(huì)令人感到聒噪,我們明明知道這個(gè)列表中的數(shù)據(jù)類(lèi)型是整數(shù)。轉(zhuǎn)換的話(huà),也把我們的代碼搞得亂七八糟。如果程序員在顯式轉(zhuǎn)換中出錯(cuò),則可能會(huì)導(dǎo)致拋出與 類(lèi)型相關(guān)的運(yùn)行時(shí)錯(cuò)誤 。

如果程序員能夠表達(dá)他們使用特定類(lèi)型的意圖,并且編譯器能夠確保這種類(lèi)型的正確性,那么這將更加容易。

這就是泛型背后的核心思想。

我們將前面代碼段的第一行修改為:

 
 
 
 
  1. List list = new LinkedList<>(); 

通過(guò)添加包含類(lèi)型的菱形運(yùn)算符<>,我們將此列表的特化范圍縮小到 Integer 類(lèi)型,即指定將保存在列表中的類(lèi)型。編譯器可以在編譯時(shí)強(qiáng)制執(zhí)行該類(lèi)型。

在較小的程序中,這看起來(lái)像是一個(gè)微不足道的添加。但是在較大的程序中,這可以增加顯著的健壯性并使程序更易于閱讀。

3. 泛型方法

泛型方法是用單個(gè)方法聲明編寫(xiě)的方法,可以用不同類(lèi)型的參數(shù)調(diào)用。編譯器將確保所用類(lèi)型的正確性。以下是泛型方法的一些屬性:

  • 泛型方法在方法聲明的返回類(lèi)型之前有一個(gè)類(lèi)型參數(shù)(包裹類(lèi)型的菱形運(yùn)算符)
  • 類(lèi)型參數(shù)可以有界(邊界將在本文后面解釋)
  • 泛型方法可以具有不同的類(lèi)型參數(shù),這些參數(shù)在方法簽名中用逗號(hào)分隔
  • 泛型方法的方法體與普通方法一樣

定義將數(shù)組轉(zhuǎn)換為列表的泛型方法的示例:

 
 
 
 
  1. public  List fromArrayToList(T[] a) {    
  2.     return Arrays.stream(a).collect(Collectors.toList()); 

在前面的示例中,方法聲明中的 表示該方法將處理泛型類(lèi)型 T。即使方法返回的是void,也需要這樣做。如上所述,方法可以處理多個(gè)泛型類(lèi)型,在這種情況下,所有泛型類(lèi)型都必須添加到方法聲明中,例如,如果我們要修改上面的方法來(lái)處理類(lèi)型 T 和類(lèi)型 G ,應(yīng)該這樣寫(xiě):

 
 
 
 
  1. public static  List fromArrayToList(T[] a, Function mapperFunction) { 
  2.     return Arrays.stream(a) 
  3.       .map(mapperFunction) 
  4.       .collect(Collectors.toList()); 

我們正在傳遞一個(gè)函數(shù),該函數(shù)將具有T類(lèi)型元素的數(shù)組轉(zhuǎn)換為包含G類(lèi)型元素的列表。例如,將 Integer 轉(zhuǎn)換為其 String 表示形式:

 
 
 
 
  1. @Test 
  2. public void givenArrayOfIntegers_thanListOfStringReturnedOK() { 
  3.     Integer[] intArray = {1, 2, 3, 4, 5}; 
  4.     List stringList 
  5.       = Generics.fromArrayToList(intArray, Object::toString); 
  6.   
  7.     assertThat(stringList, hasItems("1", "2", "3", "4", "5")); 

Oracle建議使用大寫(xiě)字母表示泛型類(lèi)型,并選擇更具描述性的字母來(lái)表示形式類(lèi)型,例如在Java集合中,T 用于類(lèi)型,K 表示鍵,V 表示值。

3.1.泛型邊界

如前所述,類(lèi)型參數(shù)可以是有界的。有界意味著“限制”,我們可以限制方法可以接受的類(lèi)型。

例如,可以指定一個(gè)方法接受一個(gè)類(lèi)型及其所有子類(lèi)(上限)或一個(gè)類(lèi)型所有它的超類(lèi)(下限)。

要聲明上界類(lèi)型,我們?cè)陬?lèi)型后面使用關(guān)鍵字extends,后跟要使用的上限。例如:

 
 
 
 
  1. public  List fromArrayToList(T[] a) { 
  2.     ... 

這里使用關(guān)鍵字extends表示類(lèi)型 T 擴(kuò)展類(lèi)的上限,或者實(shí)現(xiàn)接口的上限。

3.2. 多個(gè)邊界

類(lèi)型還可以有多個(gè)上界,如下所示:

如果 T 擴(kuò)展的類(lèi)型之一是類(lèi)(即Number),則必須將其放在邊界列表的第一位。否則,將導(dǎo)致編譯時(shí)錯(cuò)誤。

4. 使用通配符

通配符在Java中用問(wèn)號(hào)“?“ 表示,它們是用來(lái)指一種未知的類(lèi)型。通配符在使用泛型時(shí)特別有用,可以用作參數(shù)類(lèi)型,但首先要考慮的是一個(gè)重要的注釋。

眾所周知,Object是所有Java類(lèi)的超類(lèi)型,但是,Object的集合不是任何集合的超類(lèi)型。(可能有點(diǎn)繞,大家好好細(xì)品一下)

例如,List 不是 List 的超類(lèi)型,將List類(lèi)型的變量賦值給List 類(lèi)型的變量將導(dǎo)致編譯器錯(cuò)誤。

這是為了防止在將異構(gòu)類(lèi)型添加到同一集合時(shí)可能發(fā)生的沖突。

相同的規(guī)則適用于類(lèi)型及其子類(lèi)型的任何集合??纯催@個(gè)例子:

 
 
 
 
  1. public static void paintAllBuildings(List buildings) { 
  2.     buildings.forEach(Building::paint); 

如果我們?cè)O(shè)想一個(gè)子類(lèi)型Building,實(shí)例House,那么我們不能將此方法與House列表一起使用,即使House是Building的子類(lèi)型。如果需要將此方法與類(lèi)型構(gòu)建及其所有子類(lèi)型一起使用,則有界通配符可以實(shí)現(xiàn)以下功能:

 
 
 
 
  1. public static void paintAllBuildings(List buildings) { 
  2.     ... 

現(xiàn)在,這個(gè)方法可以處理Building類(lèi)型及其所有子類(lèi)型。這稱(chēng)為上界通配符,其中類(lèi)型Building是上界。

通配符也可以使用下限指定,其中未知類(lèi)型必須是指定類(lèi)型的超類(lèi)型??梢允褂胹uper關(guān)鍵字后跟特定類(lèi)型來(lái)指定下限,例如, 表示未知類(lèi)型,它是 T(=T及其所有父類(lèi))的超類(lèi)。

5. 類(lèi)型擦除

泛型被添加到Java中以確保類(lèi)型安全,并確保泛型不會(huì)在運(yùn)行時(shí)造成開(kāi)銷(xiāo),編譯器在編譯時(shí)對(duì)泛型應(yīng)用一個(gè)名為type erasure的進(jìn)程。

類(lèi)型擦除刪除所有類(lèi)型參數(shù),并將其替換為它們的邊界,如果類(lèi)型參數(shù)是無(wú)界的,則替換為Object。因此,編譯后的字節(jié)碼只包含普通的類(lèi)、接口和方法,從而確保不會(huì)生成新的類(lèi)型。在編譯時(shí)對(duì)Object類(lèi)型也應(yīng)用了正確的強(qiáng)制轉(zhuǎn)換。以下是類(lèi)型擦除的一個(gè)示例:

 
 
 
 
  1. public  List genericMethod(List list) { 
  2.     return list.stream().collect(Collectors.toList()); 

使用類(lèi)型擦除,無(wú)界類(lèi)型T將替換為Object,如下所示:

 
 
 
 
  1. // for illustration 
  2. public List withErasure(List list) { 
  3.     return list.stream().collect(Collectors.toList()); 
  4.   
  5. // which in practice results in 
  6. public List withErasure(List list) { 
  7.     return list.stream().collect(Collectors.toList()); 
  8. 如果類(lèi)型是有界的,則在編譯時(shí)該類(lèi)型將替換為綁定:

     
     
     
     
    1. public  void genericMethod(T t) { 
    2.     ... 

    編譯后會(huì)發(fā)生變化:

     
     
     
     
    1. public void genericMethod(Building t) { 
    2.     ... 

    6. 泛型和原始數(shù)據(jù)類(lèi)型

    Java中泛型的一個(gè)限制是類(lèi)型參數(shù)不能是基本類(lèi)型

    例如,以下內(nèi)容無(wú)法編譯:

     
     
     
     
    1. List list = new ArrayList<>(); 
    2. list.add(17); 

    為了理解原始數(shù)據(jù)類(lèi)型為什么不起作用,只需記住 泛型是編譯時(shí)特性,這意味著類(lèi)型將會(huì)被擦除,所有泛型類(lèi)型都實(shí)現(xiàn)為 Object 類(lèi)。舉一個(gè)例子,讓我們看看列表的 add 方法:

     
     
     
     
    1. List list = new ArrayList<>(); 
    2. list.add(17); 

    add 方法的聲明如下:

     
     
     
     
    1. boolean add(E e); 

    并將被編譯為:

     
     
     
     
    1. boolean add(Object e); 

    因此,類(lèi)型參數(shù)必須可轉(zhuǎn)換為Object。由于基本類(lèi)型不繼承自 Object,所以不能將它們用作類(lèi)型參數(shù) 但是,Java為它們提供了裝箱類(lèi)型,以及自動(dòng)裝箱和自動(dòng)拆箱:

     
     
     
     
    1. Integer a = 17; 
    2. int b = a; 

    因此,如果我們想創(chuàng)建一個(gè)可以保存整數(shù)的列表,我們可以使用包裝器:

     
     
     
     
    1. List list = new ArrayList<>(); 
    2. list.add(17); 
    3. int first = list.get(0); 

    編譯后的代碼相當(dāng)于:

     
     
     
     
    1. List list = new ArrayList<>(); 
    2. list.add(Integer.valueOf(17)); 
    3. int first = ((Integer) list.get(0)).intValue(); 

    Java的未來(lái)版本可能允許泛型使用原始數(shù)據(jù)類(lèi)型。Valhalla 工程旨在改進(jìn)處理泛型的方式。其思想是實(shí)現(xiàn)JEP 218中描述的泛型專(zhuān)門(mén)化.

    7. 總結(jié)

    Java泛型是對(duì)Java語(yǔ)言的一個(gè)強(qiáng)大的補(bǔ)充,因?yàn)樗钩绦騿T的工作更容易,也更不容易出錯(cuò)。泛型在編譯時(shí)強(qiáng)制執(zhí)行類(lèi)型正確性,并且,最重要的是,能夠?qū)崿F(xiàn)泛型算法,而不會(huì)給我們的應(yīng)用程序帶來(lái)任何額外的開(kāi)銷(xiāo)。

    本文轉(zhuǎn)載自微信公眾號(hào)「鍋外的大佬」,可以通過(guò)以下二維碼關(guān)注。轉(zhuǎn)載本文請(qǐng)聯(lián)系鍋外的大佬公眾號(hào)。 


    文章標(biāo)題:重溫Java泛型,帶你更深入地理解它,更好的使用它!
    標(biāo)題鏈接:http://www.5511xx.com/article/ccdcjjs.html