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

年后跑路第一戰,從 Java 泛型學起!

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

[[433095]]

文末本文轉載自微信公眾號「愛寫Bug的麥洛」,作者麥洛  。轉載本文請聯系愛寫Bug的麥洛公眾號。

概述

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

為什么要引入泛型?

在沒有泛型的背景下,讓我們想象一個場景,我們要在 Java 中創建一個List來存儲Integer。

代碼如下:

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

果不其然,IDEA會直接提醒需要強制轉換。

我們對代碼進行修改,如下所示:

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

在沒有泛型的前提下,定義的List可以保存任何對象,當我們遍歷時候,根據上下文進行判斷,只能保證它是一個Object,所以需要我們顯示轉換。

我們知道List中的數據類型是Integer,可以直接強制轉換,如果我們不知道或者強制轉換時候寫錯類型,就會導致報錯,一場災難就這樣發生了。

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

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

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

通過添加包含類型的菱形運算符 <>,我們將List能保存的類型限制到只有Integer類型,編譯器可以在編譯時強制執行類型。

泛型方法

對于泛型方法,我們可以用不同類型的參數調用它們。編譯器將確保我們使用的任何類型的正確性。

泛型方法屬性:

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

這是定義將數組轉換為List的泛型方法的示例:

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

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

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

以下是我們如何修改上述方法以處理類型T和類型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()); 

我們正在傳遞一個函數,該函數將具有T類型元素的數組轉換為具有G類型元素的列表。

一個例子是將Integer轉換為它的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")); 

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

有界泛型

類型參數可以有界,我們可以限制方法接受的類型。例如,我們可以指定一個方法接受一個類型及其所有子類(上限)或一個類型及其所有超類(下限)。要聲明上界類型,我們在類型后使用關鍵字extends,要聲明下界類型,我們在類型后使用關鍵字super。

例子:

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

我們在這里使用關鍵字 extends 表示類型 T 在類的情況下擴展上限或在接口的情況下實現上限。

多重邊界

一個類型也可以有多個上限:

如果T擴展的類型之一是一個類(例如Number),我們必須將它放在邊界列表中的第一個。否則會導致編譯時錯誤。

在泛型中使用通配符

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

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

例子:

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

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

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

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

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

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

類型擦除

Java 中添加了泛型以確保類型安全。并且為了確保泛型不會在運行時造成開銷,編譯器在編譯時對泛型應用了一個稱為類型擦除的過程。

如果類型參數是無界的,則類型擦除會刪除所有類型參數并用它們的邊界或Object替換它們。這樣,編譯后的字節碼只包含正常的類、接口和方法,確保不會產生新的類型。在編譯時也將正確的轉換應用于 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()); 

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

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

編譯后:

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

泛型和原始數據類型

Java 中泛型的一個限制是類型參數不能是基本類型。

例如,以下不能編譯:

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

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

我們來看 一個列表的add方法:

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

add方法的簽名是:

  1. boolean add(E e); 

并將被編譯為:

  1. boolean add(Object e); 

因此,類型參數必須可轉換為Object。由于基本類型不擴展Object,我們不能將它們用作類型參數。

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

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

所以,如果我們想創建一個可以容納整數的列表,我們可以使用這個包裝器:

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

編譯后的代碼將等效于以下內容:

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

結論 

Java 泛型是對 Java 語言的強大補充,因為它使程序員的工作更輕松且不易出錯。泛型在編譯時強制類型正確,最重要的是,可以實現泛型算法而不會對我們的應用程序造成任何額外開銷。

 

責任編輯:武曉燕 來源: 愛寫Bug的麥洛
相關推薦

2013-08-07 14:19:39

移動互聯網BAT三巨頭移動市場

2009-04-21 14:43:31

2016-11-10 11:19:23

阿里云計算大數據

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

大數據人工智能技術

2024-06-20 07:38:44

2022-03-12 15:03:59

存儲閃存硬盤數據中心

2015-09-28 17:20:12

智慧

2019-12-30 09:14:54

張一鳴互聯網高管

2024-10-22 16:59:07

2012-02-27 10:17:25

2013-09-13 09:19:36

微軟IBM惠普

2010-10-09 09:19:30

2016-12-16 10:55:19

2019-01-28 11:35:45

媒體營銷
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 欧美日韩专区 | www97影院| 福利久久| 日韩免费视频一区二区 | 成年男女免费视频网站 | 久久天天| 国内精品在线视频 | 亚洲在线一区 | 精品不卡 | 免费性视频 | 免费亚洲成人 | 免费黄色的网站 | 请别相信他免费喜剧电影在线观看 | 蜜桃在线视频 | 国产综合第一页 | 狠狠综合久久av一区二区小说 | 日韩欧美在线一区 | 亚洲精品视频一区 | 亚洲免费观看 | 中文字幕一区在线 | av福利网站| 有码一区 | 国产在线不卡 | 久久男人| 亚洲视频欧美视频 | 日韩在线视频播放 | 99精品热视频 | 一区二区亚洲 | 蜜桃av一区二区三区 | 欧美一区二区三区在线观看视频 | 日韩一三区| 91视频在线看 | h在线播放| 亚洲久在线 | 91在线最新 | 亚洲天堂影院 | 成人av电影在线观看 | 精品91久久 | 在线观看的av | www.操.com | 精品久久久久久久久久 |