日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

java使用泛型后消除泛型_如何以及何时使用泛型

發(fā)布時間:2023/12/3 编程问答 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java使用泛型后消除泛型_如何以及何时使用泛型 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

java使用泛型后消除泛型

本文是我們名為“ 高級Java ”的學院課程的一部分。

本課程旨在幫助您最有效地使用Java。 它討論了高級主題,包括對象創(chuàng)建,并發(fā),序列化,反射等。 它將指導您完成Java掌握的旅程! 在這里查看 !

目錄

1.簡介 2.泛型和接口 3.泛型和類 4.泛型和方法 5.仿制藥的局限性 6.泛型,通配符和有界類型 7.泛型和類型推斷 8.泛型和注釋 9.訪問泛型類型參數 10.何時使用泛型 11.下一步 12.下載源代碼

1.簡介

泛型的概念表示對類型的抽象(C ++開發(fā)人員將其稱為模板)。 這是一個非常強大的概念(很久以前就出現了),它允許開發(fā)抽象算法和數據結構,并提供具體類型以供以后使用。 有趣的是,泛型在Java的早期版本中不存在,并且僅在Java 5版本中才添加。 從那以后,可以說,泛型徹底改變了Java程序的編寫方式,提供了更強的類型保證,并使代碼更加安全。

在本節(jié)中,我們將從接口,類和方法開始介紹泛型的用法。 提供了很多好處,但是泛型確實引入了一些局限性和副作用,我們也將介紹這些局限性和副作用。

2.泛型和接口

與常規(guī)接口相反,要定義通用接口,只需提供應使用其進行參數化的類型即可。 例如:

package com.javacodegeeks.advanced.generics;public interface GenericInterfaceOneType< T > {void performAction( final T action ); }

GenericInterfaceOneType用單一類型T參數化,可以由接口聲明立即使用。 該接口可以使用多種類型進行參數化,例如:

package com.javacodegeeks.advanced.generics;public interface GenericInterfaceSeveralTypes< T, R > {R performAction( final T action ); }

每當任何類想要實現該接口時,它都可以選擇提供確切的類型替換,例如ClassImplementingGenericInterface類提供String作為通用接口的類型參數T :

package com.javacodegeeks.advanced.generics;public class ClassImplementingGenericInterfaceimplements GenericInterfaceOneType< String > {@Overridepublic void performAction( final String action ) {// Implementation here} }

Java標準庫有很多通用接口的示例,主要是在集合庫中。 這是很容易聲明和使用通用接口,但是我們將討論界類型(如果要回他們再次泛型,通配符和有界類型 )和通用限制( 仿制藥的限制 )。

3.泛型和類

與接口相似,常規(guī)類和泛型類之間的區(qū)別僅在于類定義中的類型參數。 例如:

package com.javacodegeeks.advanced.generics;public class GenericClassOneType< T > {public void performAction( final T action ) {// Implementation here} }

請注意,可以使用泛型對任何類( 具體抽象最終 )進行參數化。 一個有趣的細節(jié)是,該類可以將(或不可以)將其泛型類型傳遞給接口和父類,而無需提供確切的類型實例,例如:

package com.javacodegeeks.advanced.generics;public class GenericClassImplementingGenericInterface< T >implements GenericInterfaceOneType< T > {@Overridepublic void performAction( final T action ) {// Implementation here} }

這是一種非常方便的技術,它允許類在仍然符合接口(或父類)協定的泛型類型上施加附加界限,這將在“ 泛型,通配符和有界類型”部分中看到。

4.泛型和方法

在討論類和接口時,我們已經在上一節(jié)中看到了幾個通用方法。 但是,關于它們還有更多的話要說。 方法可以將泛型用作參數聲明或返回類型聲明的一部分。 例如:

public< T, R > R performAction( final T action ) {final R result = ...;// Implementation herereturn result; }

對于可以使用泛型類型的方法沒有任何限制,它們可以是具體的, 抽象的靜態(tài)的final的 。 這是幾個示例:

protected abstract< T, R > R performAction( final T action );static< T, R > R performActionOn( final Collection< T > action ) {final R result = ...;// Implementation herereturn result; }

如果方法被聲明(或定義)為通用接口或類的一部分,則它們可以(也可以不)使用其所有者的通用類型。 他們可以定義自己的通用類型,也可以將其與類或接口聲明中的類型混合使用。 例如:

package com.javacodegeeks.advanced.generics;public class GenericMethods< T > {public< R > R performAction( final T action ) {final R result = ...;// Implementation herereturn result;}public< U, R > R performAnotherAction( final U action ) {final R result = ...;// Implementation herereturn result;} }

類構造函數也被認為是一種初始化方法,因此,可以使用其類聲明的泛型類型,聲明自己的泛型類型或僅將兩者混合使用(但是它們不能返回值,因此返回類型參數化不適用于構造函數), 例如:

public class GenericMethods< T > {public GenericMethods( final T initialAction ) {// Implementation here}public< J > GenericMethods( final T initialAction, final J nextAction ) {// Implementation here} }

它看起來非常簡單,而且確實如此。 但是,由于使用Java語言實現泛型的方式存在一些限制和副作用,下一部分將解決該問題。

5.仿制藥的局限性

不幸的是,泛型是語言的最鮮明的特征之一,它有一些局限性,這主要是由于泛型很晚才引入已經很成熟的語言。 最可能的是,更徹底的實施需要大量的時間和資源,因此需要進行權衡,以便及時提供仿制藥。

首先,在泛型中不允許使用原始類型(例如int , long , byte等等)。 這意味著無論何時需要使用原始類型參數化泛型類型時,都必須使用相應的類包裝器( Integer , Long , Byte …)代替。

final List< Long > longs = new ArrayList<>(); final Set< Integer > integers = new HashSet<>();

不僅如此,由于必須在泛型中使用類包裝器,因此會導致對原始值進行隱式裝箱和拆箱(本教程的第7部分“ 常規(guī)編程指南”中將詳細介紹此主題),例如:

final List< Long > longs = new ArrayList<>(); longs.add( 0L ); // 'long' is boxed to 'Long'long value = longs.get( 0 ); // 'Long' is unboxed to 'long' // Do something with value

但是原始類型只是泛型陷阱之一。 另一個更晦澀的是類型擦除。 重要的是要知道泛型僅在編譯時存在:Java編譯器使用一組復雜的規(guī)則來強制有關泛型及其類型參數使用的類型安全,但是所產生的JVM字節(jié)碼已擦除了所有具體類型(并替換為Object類)。 首先,以下代碼無法編譯可能令人驚訝:

void sort( Collection< String > strings ) {// Some implementation over strings heres }void sort( Collection< Number > numbers ) {// Some implementation over numbers here }

從開發(fā)人員的角度來看,這是一個完全有效的代碼,但是由于類型擦除,這兩種方法的范圍縮小到了相同的簽名,并導致編譯錯誤(帶有奇怪的消息,如“方法的擦除sort(Collection <String> )與另一種方法相同……” ):

void sort( Collection strings ) void sort( Collection numbers )

由類型擦除引起的另一個缺點來自這樣一個事實,即不可能以任何有意義的方式使用泛型的類型參數,例如,無法創(chuàng)建類型的新實例,或者獲取類型參數的具體類或在類型參數中使用它。 instanceof運算符。 下面顯示的示例沒有通過編譯階段:

public< T > void action( final T action ) {if( action instanceof T ) {// Do something here} }public< T > void action( final T action ) {if( T.class.isAssignableFrom( Number.class ) ) {// Do something here} }

最后,使用泛型的類型參數創(chuàng)建數組實例也是不可能的。 例如,以下代碼無法編譯(這時出現一條清晰的錯誤消息“無法創(chuàng)建T的通用數組” ):

public< T > void performAction( final T action ) {T[] actions = new T[ 0 ]; }

盡管有所有這些限制,但泛型仍然非常有用,并帶來了很多價值。 在“ 訪問泛型類型參數 ”一節(jié)中,我們將介紹幾種克服Java語言中的泛型實現所施加的一些約束的方法。

6.泛型,通配符和有界類型

到目前為止,我們已經看到了使用具有無限制類型參數的泛型的示例。 泛型的強大功能是將約束(或界限)強加在使用extends和super關鍵字對其進行參數化的類型上。

extends關鍵字將type參數限制為其他某個類的子類或實現一個或多個接口。 例如:

public< T extends InputStream > void read( final T stream ) {// Some implementation here }

read方法聲明中的類型參數T必須是InputStream類的子類。 相同的關鍵字用于限制接口實現。 例如:

public< T extends Serializable > void store( final T object ) {// Some implementation here }

方法存儲區(qū)需要其類型參數T來實現Serializable接口,以便該方法執(zhí)行所需的操作。 也可以使用其他類型參數作為extends關鍵字的綁定,例如:

public< T, J extends T > void action( final T initial, final J next ) {// Some implementation here }

邊界不限于單個約束,可以使用&運算符進行組合。 可能指定了多個接口,但僅允許單個類。 類和接口的組合也是可能的,下面顯示了兩個示例:

public< T extends InputStream & Serializable > void storeToRead( final T stream ) {// Some implementation here } public< T extends Serializable & Externalizable & Cloneable > void persist(final T object ) {// Some implementation here }

在討論super關鍵字之前,我們需要熟悉通配符的概念。 如果類型參數與通用類,接口或方法不相關,則可以將其替換為?。 通配符。 例如:

public void store( final Collection< ? extends Serializable > objects ) {// Some implementation here }

方法store并不真正在乎調用它的類型參數,唯一需要確保每個類型都實現Serializable接口的方法。 或者,如果這不重要,則可以使用無界通配符:

public void store( final Collection< ? > objects ) {// Some implementation here }

與extends相反, super關鍵字將type參數限制為某個其他類的超類。 例如:

public void interate( final Collection< ? super Integer > objects ) {// Some implementation here }

通過使用類型上限和下限(具有extends和super )以及類型通配符,泛型提供了一種微調類型參數要求的方法,或者在某些情況下完全忽略了它們,仍然保留了面向類型的語義。

7.泛型和類型推斷

當泛型進入Java語言時,它們消耗了開發(fā)人員為滿足語言語法規(guī)則而必須編寫的代碼量。 例如:

final Map< String, Collection< String > > map =new HashMap< String, Collection< String > >();for( final Map.Entry< String, Collection< String > > entry: map.entrySet() ) {// Some implementation here }

Java 7版本通過在編譯器中進行更改并引入了新的菱形運算符<>,在某種程度上解決了該問題。 例如:

final Map< String, Collection< String > > map = new HashMap<>();

編譯器能夠從左側推斷泛型類型參數,并允許在表達式的右側省略它們。 在使泛型語法不那么冗長方面,這是一個重大進步,但是編譯器推斷泛型類型參數的能力非常有限。 例如,以下代碼無法在Java 7中編譯:

public static < T > void performAction( final Collection< T > actions,final Collection< T > defaults ) {// Some implementation here }final Collection< String > strings = new ArrayList<>(); performAction( strings, Collections.emptyList() );

Java 7編譯器無法推斷Collections. emptyList ()的type參數Collections. emptyList () Collections. emptyList ()調用,因此需要將其顯式傳遞:

performAction( strings, Collections.< String >emptyList() );

幸運的是,Java 8版本為編譯器,尤其是對泛型的類型推斷帶來了更多增強,因此上面顯示的代碼片段成功編譯,從而使開發(fā)人員不必進行不必要的鍵入。

8.泛型和注釋

盡管我們將在本教程的下一部分中討論注釋,但是值得一提的是,在Java 8之前的時代,泛型不允許其類型參數與注釋關聯。 但是Java 8改變了這一點,現在可以在聲明或使用它們的地方注釋泛型類型參數。 例如,以下是如何聲明泛型方法并在其類型參數上標注注釋的方法:

public< @Actionable T > void performAction( final T action ) {// Some implementation here }

或只是使用泛型類型時應用注釋的另一個示例:

final Collection< @NotEmpty String > strings = new ArrayList<>(); // Some implementation here

在本教程的第4部分“ 如何以及何時使用Enums和Annotations”中 ,我們將看幾個示例如何使用注釋以將某些元數據與泛型類型參數相關聯。 本節(jié)僅使您感到可以通過注釋豐富泛型。

9.訪問泛型類型參數

正如您從“ 泛型的限制 ”一節(jié)中已經知道的那樣,不可能獲得泛型類型參數的類。 解決此問題的一個簡單技巧是,在需要知道類型參數T的類的地方,需要傳遞其他參數Class< T > 。 例如:

public< T > void performAction( final T action, final Class< T > clazz ) {// Some implementation here }

它可能會浪費方法所需的參數量,但經過精心設計,它并不像乍看上去那樣糟糕。

在Java中使用泛型時經常會出現的另一個有趣的用例是,確定泛型實例已被參數化的類型的具體類。 它不是那么簡單,并且需要包含Java反射API。 我們將在本教程的第11部分中查看完整示例,即反射和動態(tài)語言支持,但現在僅提及ParameterizedType實例是對泛型進行反射的中心點。

10.何時使用泛型

盡管有所有限制,但泛型為Java語言增加的價值卻是巨大的。 如今,很難想象曾經有一段時間Java沒有泛型支持。 應該使用泛型而不是原始類型(用Collection< T >代替Collection ,用Callable< T >代替Callable ……)或Object來保證類型安全,在合同和算法上定義明確的類型約束,并顯著簡化代碼維護和重構。

但是,請注意Java當前泛型實現的局限性,類型擦除以及著名的原始類型隱式裝箱和拆箱。 泛型不是解決您可能遇到的所有問題的靈丹妙藥,沒有什么可以代替精心設計和周到的思考。

查看一些真實的示例并了解泛型如何使Java開發(fā)人員的生活更輕松是一個好主意。

示例1 :讓我們考慮該方法的典型示例,該方法針對實現某個接口(例如Serializable )的類的實例執(zhí)行操作并返回該類的修改后的實例。

class SomeClass implements Serializable { }

如果不使用泛型,則解決方案可能如下所示:

public Serializable performAction( final Serializable instance ) {// Do something herereturn instance; } final SomeClass instance = new SomeClass(); // Please notice a necessary type cast required final SomeClass modifiedInstance = ( SomeClass )performAction( instance );

讓我們看看泛型如何改進此解決方案:

public< T extends Serializable > T performAction( final T instance ) {// Do something herereturn instance; } final SomeClass instance = new SomeClass(); final SomeClass modifiedInstance = performAction( instance );

丑陋的類型轉換已不復存在,因為編譯器能夠推斷出正確的類型并證明這些類型已正確使用。

示例2:該方法的示例更為復雜,該示例要求類的實例實現兩個接口(例如Serializable和Runnable )。

class SomeClass implements Serializable, Runnable {@Overridepublic void run() {// Some implementation} }

不使用泛型,直接的解決方案是引入中間接口(或將純Object作為最后的手段),例如:

// The class itself should be modified to use the intermediate interface // instead of direct implementations class SomeClass implements SerializableAndRunnable {@Overridepublic void run() {// Some implementation} } public void performAction( final SerializableAndRunnable instance ) {// Do something here }

盡管這是一個有效的解決方案,但它并不是最佳選擇,并且隨著接口數量的增加,它可能會變得非常討厭和難以管理。 讓我們看看泛型如何在這里提供幫助:

public< T extends Serializable & Runnable > void performAction( final T instance ) {// Do something here }

代碼非常簡潔明了,不需要任何中間接口或其他技巧。

泛型使代碼易于閱讀和直接的示例世界真是無窮無盡。 在本教程的下一部分中,通常將使用泛型來演示Java語言的其他功能。

11.下一步

在本節(jié)中,我們介紹了Java語言的一個非常與眾不同的特性,稱為泛型。 我們已經檢查了泛型如何通過檢查正確的類型(帶有邊界)是否在各處使用來使代碼安全且簡潔。 我們還研究了一些泛型限制以及克服這些限制的方法。 在下一節(jié)中,我們將討論枚舉和注釋。

12.下載源代碼

  • 這是關于如何設計類和接口的課程。 您可以在此處下載源代碼: advanced-java-part-4

翻譯自: https://www.javacodegeeks.com/2015/09/how-and-when-to-use-generics.html

java使用泛型后消除泛型

總結

以上是生活随笔為你收集整理的java使用泛型后消除泛型_如何以及何时使用泛型的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。