自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

年后跑路第一戰(zhàn),從 Java 泛型學(xué)起!

開發(fā) 后端
本文章是對(duì) Java 中泛型的快速介紹,包含泛型背后的目標(biāo)以及使用泛型如何提高我們代碼的質(zhì)量。

[[433095]]

文末本文轉(zhuǎn)載自微信公眾號(hào)「愛寫B(tài)ug的麥洛」,作者麥洛  。轉(zhuǎn)載本文請(qǐng)聯(lián)系愛寫B(tài)ug的麥洛公眾號(hào)。

概述

大家好,我是麥洛,今天來復(fù)習(xí)一下泛型。JDK 5.0 引入了 Java 泛型,允許設(shè)計(jì)者詳細(xì)地描述變量和方法的類型要如何變化,使得代碼具有更好的可讀性。本文章是對(duì) Java 中泛型的快速介紹,包含泛型背后的目標(biāo)以及使用泛型如何提高我們代碼的質(zhì)量。

為什么要引入泛型?

在沒有泛型的背景下,讓我們想象一個(gè)場(chǎng)景,我們要在 Java 中創(chuàng)建一個(gè)List來存儲(chǔ)Integer。

代碼如下:

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

果不其然,IDEA會(huì)直接提醒需要強(qiáng)制轉(zhuǎn)換。

我們對(duì)代碼進(jìn)行修改,如下所示:

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

在沒有泛型的前提下,定義的List可以保存任何對(duì)象,當(dāng)我們遍歷時(shí)候,根據(jù)上下文進(jìn)行判斷,只能保證它是一個(gè)Object,所以需要我們顯示轉(zhuǎn)換。

我們知道List中的數(shù)據(jù)類型是Integer,可以直接強(qiáng)制轉(zhuǎn)換,如果我們不知道或者強(qiáng)制轉(zhuǎn)換時(shí)候?qū)戝e(cuò)類型,就會(huì)導(dǎo)致報(bào)錯(cuò),一場(chǎng)災(zāi)難就這樣發(fā)生了。

這時(shí)候,就有人想了,我能不能在使用List時(shí)候就指定保存的類型,編譯階段來幫我保證類型的正確性,那就可以完全避免讓人討厭的強(qiáng)制轉(zhuǎn)換,所以,泛型就因運(yùn)而生了。

讓我們修改前面代碼片段的第一行:

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

通過添加包含類型的菱形運(yùn)算符 <>,我們將List能保存的類型限制到只有Integer類型,編譯器可以在編譯時(shí)強(qiáng)制執(zhí)行類型。

泛型方法

對(duì)于泛型方法,我們可以用不同類型的參數(shù)調(diào)用它們。編譯器將確保我們使用的任何類型的正確性。

泛型方法屬性:

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

這是定義將數(shù)組轉(zhuǎn)換為L(zhǎng)ist的泛型方法的示例:

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

方法簽名中的表明該方法將處理泛型類型T。即使該方法返回 void,這也是必需的。

如前所述,該方法可以處理多個(gè)泛型類型。在這種情況下,我們必須將所有泛型類型添加到方法簽名中。

以下是我們?nèi)绾涡薷纳鲜龇椒ㄒ蕴幚眍愋蚑和類型G:

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

我們正在傳遞一個(gè)函數(shù),該函數(shù)將具有T類型元素的數(shù)組轉(zhuǎn)換為具有G類型元素的列表。

一個(gè)例子是將Integer轉(zhuǎn)換為它的String表示:

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

請(qǐng)注意,Oracle 建議使用大寫字母來表示泛型類型,并選擇更具描述性的字母來表示正式類型。在 Java 集合中,我們使用T表示類型,K表示鍵,V表示值。

有界泛型

類型參數(shù)可以有界,我們可以限制方法接受的類型。例如,我們可以指定一個(gè)方法接受一個(gè)類型及其所有子類(上限)或一個(gè)類型及其所有超類(下限)。要聲明上界類型,我們?cè)陬愋秃笫褂藐P(guān)鍵字extends,要聲明下界類型,我們?cè)陬愋秃笫褂藐P(guān)鍵字super。

例子:

  1. public <T extends Number> List<T> fromArrayToList(T[] a) { 
  2.     ... 

我們?cè)谶@里使用關(guān)鍵字 extends 表示類型 T 在類的情況下擴(kuò)展上限或在接口的情況下實(shí)現(xiàn)上限。

多重邊界

一個(gè)類型也可以有多個(gè)上限:

如果T擴(kuò)展的類型之一是一個(gè)類(例如Number),我們必須將它放在邊界列表中的第一個(gè)。否則會(huì)導(dǎo)致編譯時(shí)錯(cuò)誤。

在泛型中使用通配符

在Java中,通配符由?表示,我們使用它們來指代未知類型。通配符對(duì)泛型特別有用,可以用作參數(shù)類型。

首先,我們知道Object是所有 Java 類的超類。但是,Object的集合不是任何集合的超類型。所以,一個(gè)List 不是List的超類型,二者直接沒有任何關(guān)系。

例子:

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

假如現(xiàn)在有一個(gè)Building 的子類型,叫House,我們不能將這個(gè)方法用于 House 的列表,即使 House 是 Building 的一個(gè)子類型。

如果我們需要將此方法與類型 Building 及其所有子類型一起使用,則有界通配符可以發(fā)揮作用:

  1. public static void paintAllBuildings(List<? extends Building> buildings) { 
  2.     ... 

現(xiàn)在此方法將適用于類型 Building 及其所有子類型。這稱為上限通配符,其中類型 Building 是上限。

我們還可以指定具有下限的通配符,其中未知類型必須是指定類型的超類型。可以使用 super 關(guān)鍵字后跟特定類型來指定下限。例如, 表示未知類型,它是 T 的超類(= T 及其所有父類)。

類型擦除

Java 中添加了泛型以確保類型安全。并且為了確保泛型不會(huì)在運(yùn)行時(shí)造成開銷,編譯器在編譯時(shí)對(duì)泛型應(yīng)用了一個(gè)稱為類型擦除的過程。

如果類型參數(shù)是無界的,則類型擦除會(huì)刪除所有類型參數(shù)并用它們的邊界或Object替換它們。這樣,編譯后的字節(jié)碼只包含正常的類、接口和方法,確保不會(huì)產(chǎn)生新的類型。在編譯時(shí)也將正確的轉(zhuǎn)換應(yīng)用于 Object 類型。

這是類型擦除的示例:

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

使用類型擦除,無界類型T被替換為Object:

  1. public List<Object> withErasure(List<Object> list) { 
  2.     return list.stream().collect(Collectors.toList()); 
  3.  
  4.  
  5. public List withErasure(List list) { 
  6.     return list.stream().collect(Collectors.toList()); 

如果類型是有界的,則在編譯時(shí)該類型將被邊界替換:

  1. public <T extends Building> void genericMethod(T t) { 
  2.     ... 

編譯后:

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

泛型和原始數(shù)據(jù)類型

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

例如,以下不能編譯:

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

要理解基本類型為什么不起作用,讓我們記住泛型是一個(gè)編譯時(shí)特性,這意味著類型參數(shù)被刪除并且所有泛型類型都實(shí)現(xiàn)為類型Object。

我們來看 一個(gè)列表的add方法:

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

add方法的簽名是:

  1. boolean add(E e); 

并將被編譯為:

  1. boolean add(Object e); 

因此,類型參數(shù)必須可轉(zhuǎn)換為Object。由于基本類型不擴(kuò)展Object,我們不能將它們用作類型參數(shù)。

然而,Java 為原語提供了裝箱類型,以及自動(dòng)裝箱和拆箱來解包它們:

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

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

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

編譯后的代碼將等效于以下內(nèi)容:

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

結(jié)論 

Java 泛型是對(duì) Java 語言的強(qiáng)大補(bǔ)充,因?yàn)樗钩绦騿T的工作更輕松且不易出錯(cuò)。泛型在編譯時(shí)強(qiáng)制類型正確,最重要的是,可以實(shí)現(xiàn)泛型算法而不會(huì)對(duì)我們的應(yīng)用程序造成任何額外開銷。

 

責(zé)任編輯:武曉燕 來源: 愛寫B(tài)ug的麥洛
相關(guān)推薦

2013-08-07 14:19:39

移動(dòng)互聯(lián)網(wǎng)BAT三巨頭移動(dòng)市場(chǎng)

2009-04-21 14:43:31

2016-11-10 11:19:23

阿里云計(jì)算大數(shù)據(jù)

2013-06-07 10:10:39

2015-01-27 19:16:04

2023-10-30 09:06:22

2021-10-12 16:46:59

ArrayList接口LinkedList

2015-05-18 10:53:33

2014-08-25 15:19:11

MIUI 6

2020-05-15 10:52:41

大數(shù)據(jù)人工智能技術(shù)

2024-06-20 07:38:44

2024-10-22 16:59:07

2022-03-12 15:03:59

存儲(chǔ)閃存硬盤數(shù)據(jù)中心

2015-09-28 17:20:12

智慧

2019-12-30 09:14:54

張一鳴互聯(lián)網(wǎng)高管

2012-02-27 10:17:25

2016-12-16 10:55:19

2010-10-09 09:19:30

2013-09-13 09:19:36

微軟IBM惠普

2019-08-29 09:30:20

Java泛型構(gòu)造器
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)