91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

如何掌握Java泛型

發布時間:2021-10-25 11:30:13 來源:億速云 閱讀:103 作者:iii 欄目:編程語言

本篇內容介紹了“如何掌握Java泛型”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!

 為什么要用泛型?

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

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

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

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

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

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

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

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

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

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

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

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

 泛型方法

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

  • 泛型方法在方法聲明的返回類型之前有一個類型參數(包裹類型的菱形運算符)

  • 類型參數可以有界(邊界將在本文后面解釋)

  • 泛型方法可以具有不同的類型參數,這些參數在方法簽名中用逗號分隔

  • 泛型方法的方法體與普通方法一樣

定義將數組轉換為列表的泛型方法的示例:

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

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

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

我們正在傳遞一個函數,該函數將具有T類型元素的數組轉換為包含G類型元素的列表。例如,將 Integer 轉換為其 String 表示形式:

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

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

泛型邊界

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

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

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

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

這里使用關鍵字extends表示類型 T 擴展類的上限,或者實現接口的上限。

 多個邊界

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

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

 使用通配符

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

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

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

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

相同的規則適用于類型及其子類型的任何集合。看看這個例子:

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

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

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

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

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

 類型擦除

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

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

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

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

// for illustration public List<Object> withErasure(List<Object> list) {     return list.stream().collect(Collectors.toList()); }   // which in practice results in public List withErasure(List list) {     return list.stream().collect(Collectors.toList()); }

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

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

編譯后會發生變化:

public void genericMethod(Building t) {     ... }

 泛型和原始數據類型

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

例如,以下內容無法編譯:

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

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

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

add  方法的聲明如下:

boolean add(E e);

并將被編譯為:

boolean add(Object e);

因此,類型參數必須可轉換為Object。由于基本類型不繼承自 Object,所以不能將它們用作類型參數  但是,Java為它們提供了裝箱類型,以及自動裝箱和自動拆箱:

Integer a = 17; int b = a;

因此,如果我們想創建一個可以保存整數的列表,我們可以使用包裝器:

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

編譯后的代碼相當于:

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

Java的未來版本可能允許泛型使用原始數據類型。Valhalla  工程旨在改進處理泛型的方式。其思想是實現JEP 218中描述的泛型專門化.

“如何掌握Java泛型”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

长沙市| 陵川县| 红安县| 高雄市| 二手房| 张家口市| 攀枝花市| 贵定县| 临汾市| 武功县| 连城县| 共和县| 青田县| 海丰县| 南涧| 五常市| 肥东县| 望城县| 武冈市| 安西县| 通榆县| 潼关县| 和硕县| 高阳县| 尚义县| 永和县| 大埔区| 汶川县| 南华县| 崇仁县| 承德县| 琼结县| 淮北市| 台东县| 诸城市| 兴和县| 隆安县| 吉林市| 黄陵县| 吉林省| 常德市|