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

重溫Java泛型,帶你更深入地理解它,更好的使用它!

開發(fā) 后端
Java泛型是對Java語言的一個強大的補充,因為它使程序員的工作更容易,也更不容易出錯。泛型在編譯時強制執(zhí)行類型正確性,并且,最重要的是,能夠?qū)崿F(xiàn)泛型算法,而不會給我們的應用程序帶來任何額外的開銷。

[[351275]]

 1. 引言

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

2. 為什么要用泛型?

設(shè)想一個場景,我們希望用Java創(chuàng)建一個列表來存儲Integer;代碼可能會寫成這樣:

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

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

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

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

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

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

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

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

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

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

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

3. 泛型方法

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

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

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

  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()); 

我們正在傳遞一個函數(shù),該函數(shù)將具有T類型元素的數(shù)組轉(zhuǎn)換為包含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")); 

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

3.1.泛型邊界

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

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

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

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

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

3.2. 多個邊界

類型還可以有多個上界,如下所示:

如果 T 擴展的類型之一是類(即Number),則必須將其放在邊界列表的第一位。否則,將導致編譯時錯誤。

4. 使用通配符

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

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

例如,List 不是 List的超類型,將List類型的變量賦值給List類型的變量將導致編譯器錯誤。

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

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

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

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

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

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

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

5. 類型擦除

泛型被添加到Java中以確保類型安全,并確保泛型不會在運行時造成開銷,編譯器在編譯時對泛型應用一個名為type erasure的進程。

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

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

使用類型擦除,無界類型T將替換為Object,如下所示:

  1. // for illustration 
  2. public List<Object> withErasure(List<Object> 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()); 

如果類型是有界的,則在編譯時該類型將替換為綁定:

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

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

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

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

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

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

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

為了理解原始數(shù)據(jù)類型為什么不起作用,只需記住 泛型是編譯時特性,這意味著類型將會被擦除,所有泛型類型都實現(xiàn)為 Object 類。舉一個例子,讓我們看看列表的 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。由于基本類型不繼承自 Object,所以不能將它們用作類型參數(shù) 但是,Java為它們提供了裝箱類型,以及自動裝箱和自動拆箱:

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

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

  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的未來版本可能允許泛型使用原始數(shù)據(jù)類型。Valhalla 工程旨在改進處理泛型的方式。其思想是實現(xiàn)JEP 218中描述的泛型專門化.

7. 總結(jié)

Java泛型是對Java語言的一個強大的補充,因為它使程序員的工作更容易,也更不容易出錯。泛型在編譯時強制執(zhí)行類型正確性,并且,最重要的是,能夠?qū)崿F(xiàn)泛型算法,而不會給我們的應用程序帶來任何額外的開銷。

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

 

責任編輯:武曉燕 來源: 鍋外的大佬
相關(guān)推薦

2018-05-28 09:20:10

Python迭代for循環(huán)

2017-11-14 14:41:11

Java泛型IO

2010-02-03 17:51:42

Ubuntu Linu

2023-09-20 15:12:09

2024-11-05 09:11:09

TypeScript開發(fā)者代碼

2009-06-16 11:32:00

Java泛型

2009-06-11 17:31:27

Java泛型

2020-10-20 10:17:20

Java泛型Type

2025-01-24 08:19:57

2009-03-17 16:22:13

Java泛型接口

2022-03-18 06:32:43

遞歸Python算法

2011-07-10 13:45:35

JAVA泛型

2017-11-20 11:05:23

數(shù)據(jù)庫MongoDB索引

2009-08-24 10:29:39

C# 泛型

2021-09-29 18:17:30

Go泛型語言

2021-07-09 06:11:37

Java泛型Object類型

2021-07-01 06:47:30

Java泛型泛型擦除

2020-11-02 08:51:57

中間件和洋蔥模型

2022-03-29 11:48:40

Go泛型測試

2018-01-22 17:02:48

Python字符編碼ASCII
點贊
收藏

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

主站蜘蛛池模板: 亚洲精品av在线 | 精品欧美一区二区三区精品久久 | 精品自拍视频 | 精品视频亚洲 | 成人av播放 | 欧美亚洲激情 | 日韩视频区| 久久精品—区二区三区 | 黄色网址av | 欧美日韩一区二区三区四区 | 国产片侵犯亲女视频播放 | 一区二区三区在线免费观看视频 | www.av在线| 国产在线第一页 | 中文字幕av第一页 | 在线观看你懂的网站 | 中文字幕国产高清 | 天天干免费视频 | 欧美一区二区三区在线播放 | 天天操天天摸天天爽 | 国产精品欧美一区二区三区不卡 | 找个黄色片 | 国内自拍第一页 | 久久久久久成人 | 久久99国产精一区二区三区 | 色婷婷国产精品 | 国产色婷婷精品综合在线手机播放 | 操射视频| 亚洲精选久久 | 91精品国产91久久久久游泳池 | 91精品国产一区二区三区蜜臀 | 狠狠干影院 | 91精品国产综合久久小仙女图片 | 精产国产伦理一二三区 | 久久激情视频 | 999精品视频 | 国产综合视频 | 最新av在线播放 | 蜜桃精品视频在线 | 伊人二区| 国产福利91精品 |