国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

簡述泛型的基本使用和作用

這篇具有很好參考價值的文章主要介紹了簡述泛型的基本使用和作用。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

前言

在上一篇文章中,給大家講解了泛型的概念、作用、使用場景,以及泛型集合、泛型接口和泛型類的用法,但受限于篇幅,并沒有把泛型的內(nèi)容講解完畢。所以今天我們會繼續(xù)學(xué)習(xí)泛型方法、泛型擦除,以及通配符等的內(nèi)容,希望大家繼續(xù)做好學(xué)習(xí)的準(zhǔn)備哦。


全文大約【4600】 字,不說廢話,只講可以讓你學(xué)到技術(shù)、明白原理的純干貨!本文帶有豐富的案例及配圖視頻,讓你更好地理解和運用文中的技術(shù)概念,并可以給你帶來具有足夠啟迪的思考...

一. 泛型方法

1. 簡介

我們可以在定義接口和類時使用泛型,這樣該接口和類中的所有方法及成員變量等處,也都可以使用該泛型。但其實泛型可以應(yīng)用在整個類上,也可以只應(yīng)用在類中的某個方法上。也就是說,方法所在的類可以是泛型類,也可以不是泛型類。方法中是否帶有泛型,與其所在的類有沒有泛型沒有關(guān)系。

泛型方法是在調(diào)用方法時才確定類型的方法,泛型可以使得該方法獨立于類而產(chǎn)生變化。另外,static靜態(tài)方法無法訪問泛型類的類型參數(shù),因此,如果想讓一個static方法具有泛型能力,就必須使該靜態(tài)方法成為泛型方法。

2. 語法

我們在定義泛型方法時,需要在方法名的前面添加類型參數(shù)。定義泛型方法的語法格式如下:

[訪問權(quán)限修飾符] [static] [final] <類型參數(shù)列表> 返回值類型 方法名([形式參數(shù)列表])

例如:

public static <T> List showInfo(Class<T> clazz,int userId){}

一般情況下,我們編寫泛型方法時,必須在該方法的名稱前聲明要使用的泛型,并且可以同時聲明多個泛型,中間也是用逗號分割。接下來就定義一個泛型方法,給大家具體介紹一下泛型方法的創(chuàng)建和使用。

3. 代碼案例

這里我們定義一個泛型方法,用于對數(shù)組排序后再遍歷元素輸出,代碼如下:

import java.util.Arrays;

public class Demo04 {
	
	//定義了一個靜態(tài)的泛型方法,遍歷數(shù)組中的每個元素
	public static <T> void printArray(T[] arr) {
		//先對數(shù)組進行排序
		Arrays.sort(arr);
		//再遍歷數(shù)組元素
	    for (T t : arr) {
	        System.out.print(t + " ");
	    }
	    System.out.println();
	}
	
	public static void main(String[] args) {
		Integer[] nums= {100,39,8,200,65};
		//調(diào)用泛型方法
		printArray(nums);
	}
}

在上面的代碼中,printArray()就是一個泛型方法,該方法中使用了類型參數(shù)T。并且我們在方法的參數(shù)中,使用類型參數(shù)T定義了一個泛型數(shù)組T[],接著對該數(shù)組進行排序和遍歷。這樣以后無論我們傳入任何類型的數(shù)組,都可以在不進行類型轉(zhuǎn)換的前提下,輕松實現(xiàn)排序等功能了,這樣我們之前提的需求也就很容易實現(xiàn)了。

二. 通配符

除了以上這些用法之外,泛型中還有一個很重要的通配符功能,接下來我們就來看看它是怎么回事。

1. 簡介

泛型中的通配符其實也是一種特殊的泛型類型,也稱為通配符類型參數(shù)。利用通配符類型參數(shù),可以讓我們編寫出更通用的代碼,甚至可以在不知道實際類型的情況下使用它們。我們一般是使用 ? 來代替具體的類型參數(shù),例如 List<?> 在邏輯上可以等同于 List、List 等所有 List<具體類型實參> 的類。

對此,有的小伙伴可能會很好奇,我們?yōu)槭裁葱枰ㄅ浞??其實之所以會出現(xiàn)通配符,主要是在開發(fā)時,有時候我們需要一個泛型類型,但我們卻不知道該使用哪個具體的類型。在這種情況下,我們就可以使用通配符類型參數(shù),讓代碼更加地通用。比如,我們想編寫一個可以接受任何類型的集合,并返回其中最大的元素時,此時我們可能并不確定到底該傳入哪個具體的集合,那使用通配符就會更好一些。

2. 通配符的形式

泛型通配符在具體使用時,有如下三種實現(xiàn)形式:

  • 未限定通配符(?)?表示未知類型的通配符;
  • 上限通配符(? extends T)?表示類型上限的通配符,T是一個類或接口
  • 下限通配符(? super T)?表示類型下限的通配符,T是一個類或接口

接下來我們針對以上這三種形式,分別通過幾個案例來給大家講解其用法。

3. 未限定通配符(?)

未限定通配符(?)是一種表示未知類型的通配符,它可以在需要一個類型參數(shù)的情況下使用。但由于沒有限制,因此它只能用于簡單的情況,例如集合中的迭代器或者返回類型是泛型的方法等。下面是一個簡單的例子:

import java.util.ArrayList;
import java.util.List;

public class Demo05 {

	public static void main(String[] args) {
		List<String> names = new ArrayList<String>();
		List<Integer> ages = new ArrayList<Integer>();
		List<Number> numbers = new ArrayList<Number>();

		names.add("一一哥");
		names.add("秦始皇");
		ages.add(28);
		ages.add(50);
		ages.add(28);
		numbers.add(100);
		numbers.add(800);

		printElement(names);
		printElement(ages);
		printElement(numbers);
	}

	//未限定通配符的使用
	public static void printElement(List<?> data) {
		for(int i=0;i<data.size();i++) {
			//data.getClass().getSimpleName():用于獲取某個類的類名
			System.out.println(data.getClass().getSimpleName()+"--data: " + data.get(i));
		}
	}

}

在這個例子中,printElement()方法就接受了一個未知類型的List集合,所以names,ages,numbers都可以作為這個方法的實參,這就是未限定通配符的作用。

4. PECS原則

PECS是Producer Extends Consumer Super的縮寫,這是關(guān)于Java泛型的一種設(shè)計原則。該原則表示,如果我們需要返回T,它是生產(chǎn)者(Producer),要使用extends通配符;如果需要寫入T,它就是消費者(Consumer),要使用super通配符。該原則可以指導(dǎo)我們在使用泛型時,該如何定義類型參數(shù)的上限和下限。

當(dāng)我們使用泛型時,可能需要定義類型參數(shù)的上限和下限。

例如,我們想要編寫一個方法來處理一些集合類型,但我們不知道這些集合中到底有什么類型的元素,此時我們就可以定義一個類型參數(shù)來處理所有的集合類型。一般我們可以利用extends來設(shè)置泛型上限,利用super來設(shè)置泛型下限。接下來會在下面的第5和第6小結(jié)中,給大家講解泛型的上限和下限具體該如何實現(xiàn),請大家繼續(xù)往下學(xué)習(xí)。

5. 上限通配符(? extends T)

上限通配符(?extends T)是一種表示類型上限的通配符,其中T是一個類或接口,泛型類的類型必須實現(xiàn)或繼承 T這個接口或類。它指定了可以使用的類型上限,主要是用于限制輸入的參數(shù)類型。

import java.util.ArrayList;
import java.util.List;

/**
 * @author 一一哥Sun 
 */
public class Demo06 {

	public static void main(String[] args) {
		List<String> names = new ArrayList<String>();
		List<Integer> ages = new ArrayList<Integer>();
		List<Number> numbers = new ArrayList<Number>();

		names.add("一一哥");
		names.add("秦始皇");
		ages.add(28);
		ages.add(50);
		ages.add(28);
		numbers.add(100);
		numbers.add(800);
		
		//String等非Number類型就不行
		//printElementUpbound(names);
		
		//泛型值只能是Number及其子類類型,所以Integer/Double/Float等類型都可以,但String就不行
		printElementUpbound(ages);
		printElementUpbound(numbers);
	}

	//上限通配符的使用,這里的泛型值只能是Number及其子類類型
	public static void printElementUpbound(List<? extends Number> data) {
		for(int i=0;i<data.size();i++) {
			//data.getClass().getSimpleName():用于獲取某個類的類名
			System.out.println(data.getClass().getSimpleName()+"--data: " + data.get(i));
		}
	}
}

在這個例子中,printElementUpbound方法中的集合泛型,可以是Number類或其子類,除此之外的其他類型都不行。也就是說,我們只能使用Number或其子類作為類型參數(shù),泛型類型的上限是Number,這就是上限通配符的含義。

6. 下限通配符(? super T)

下限通配符(?super T)是一種表示類型下限的通配符,其中T是一個類或接口。它指定了可以使用的類型下限,主要用于限制輸出的參數(shù)類型。下面是一個簡單的例子:

import java.util.ArrayList;
import java.util.List;

public class Demo07 {

	public static void main(String[] args) {
		List<String> names = new ArrayList<String>();
		List<Integer> ages = new ArrayList<Integer>();
		List<Double> numbers = new ArrayList<Double>();

		names.add("一一哥");
		names.add("秦始皇");
		ages.add(28);
		ages.add(50);
		ages.add(28);
		numbers.add(100.0);
		numbers.add(800.9);
		
		//String等非Number類型就不行
		//printElementUpbound(names);
		
		//此時Double類型也不行
		//printElementDownbound(numbers);
		
		//泛型值只能是Integer及其父類類型,所以Double/Float/String等類型都不可以
		printElementDownbound(ages);
		
	}

	//下限通配符的使用,這里的泛型值只能是Integer及其父類類型
	public static void printElementDownbound(List<? super Integer> data) {
		for(int i=0;i<data.size();i++) {
			System.out.println(data.getClass().getSimpleName()+"--data: " + data.get(i));
		}
	}
}

在這個例子中,printElementDownbound方法中的集合泛型,可以是Integer或其父類型,即類型下限是Integer,除此之外的其他類型都不行。也就是說,我們只能使用Integer或其父類作為類型參數(shù),泛型類型的下限是Integer,這就是下限通配符的含義。

7. <? extends T>和<? super T>的區(qū)別

在這里,要給大家再總結(jié)一下<? extends T>和<? super T>的區(qū)別:

  • <? extends T> 允許調(diào)用 T get()這樣的 讀方法來獲取 T對象 的引用,但不允許調(diào)用 set(T)這樣的 寫方法來傳入 T 的引用(傳入 null 除外);
  • <? super T> 允許調(diào)用 set(T)這樣的 寫方法傳入 T對象 的引用,但不允許調(diào)用 T get()這樣的 讀方法來獲取 T對象 的引用(獲取 Object 除外)。
  • <? extends T> 允許讀不允許寫, <? super T> 允許寫不允許讀。

大家注意,無論是未限定通配符、上限通配符還是下限通配符,我們既可以在方法中使用,也可以在類或接口中使用。

三. 泛型擦除

我們在學(xué)習(xí)泛型時,除了要掌握上面這些泛型類、泛型接口、泛型方法以及通配符等內(nèi)容之外,還要學(xué)習(xí)泛型擦除的相關(guān)內(nèi)容。那么什么是泛型擦除呢?我們繼續(xù)往下學(xué)習(xí)吧。

1. 簡介

所謂的泛型擦除(Type Erasure),就是指在編譯時,JVM編譯器會將所有的泛型信息都擦除掉,變成原始類型,一般是將泛型的類型參數(shù)替換成具體類型的上限或下限(如果沒有指定上界,則默認(rèn)為Object)。

換句話說,雖然我們在代碼中使用了泛型,但在編譯后,所有的泛型類型都會被擦除掉,轉(zhuǎn)而使用其對應(yīng)的原始類型。這就是Java泛型的底層實現(xiàn)原理。這樣設(shè)計的目的是為了兼容舊的JDK版本,使得Java具有了較好的向后兼容性,舊的非泛型代碼可以直接使用泛型類庫,而不需要進行任何修改。同時,Java也提供了反射機制來操作泛型類型,使得泛型類型在某些情況下還是可以被獲取到的,所以即使有泛型擦除,仍然也不會太影響Java虛擬機的運行時效率。

比如,在我們定義一個泛型類時,我們會使用泛型類型參數(shù)來代替具體的類型,好比下面這個例子:
簡述泛型的基本使用和作用

2. 泛型擦除帶來的限制

在編譯之后,這個泛型類的類型參數(shù)T就會被擦除,成為其對應(yīng)的原始類型Object。

這也意味著,我們無法在運行時獲取到泛型的實際類型參數(shù),所以泛型擦除的使用會有一些限制。首先由于泛型類型參數(shù)被擦除了,因此我們在運行時就無法獲得泛型類型參數(shù)的信息。例如,如果我們有一個List類型的變量,在運行時我們就無法獲得這個List集合中的元素類型是Integer。另一個限制是在使用泛型類型時,還需要注意類型安全性。在編譯階段,編譯器會檢查泛型類型的類型安全性;但在運行階段,由于泛型類型參數(shù)被擦除了,因此就無法保證類型安全性了。泛型擦除的限制,主要表現(xiàn)在以下幾個方面:

無法使用基本類型實例化類型參數(shù);

無法在運行時獲取泛型類型信息;

泛型類型參數(shù)不能用于靜態(tài)變量或靜態(tài)方法;

不能實例化T類型。

接下來再給大家具體分析一下這些限制

2.1 無法使用基本類型實例化類型參數(shù)

Java泛型中的類型參數(shù)不能是基本類型,只能是類或接口類型。例如,以下代碼在編譯階段會出錯,無法通過編譯:

List<int> list = new ArrayList<int>();

正確的寫法是使用基本類型對應(yīng)的包裝類型,如下所示:

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

2.2 無法在運行時獲取泛型類型信息

由于泛型擦除的存在,導(dǎo)致我們在程序運行時無法獲取泛型類型的信息。例如,以下代碼在運行時就無法獲取List的元素類型:

List<String> list = new ArrayList<String>(); 
Class<?> clazz = list.getClass(); 
Type type = clazz.getGenericSuperclass(); 
// 輸出:class java.util.ArrayList<E>
System.out.println(type); 

在輸出的結(jié)果中,我們只能得到ArrayList的類型信息,而無法獲取到集合中具體的泛型類型信息,也就是獲取不到String的信息。但如果我們就是想在運行時獲取到泛型的實際類型參數(shù),其實可以參考以下方式進行實現(xiàn):

public class Box<T> {
    private T content;

    public Box(T content) {
        this.content = content;
    }

    public T getContent() {
        return content;
    }

    public void setContent(T content) {
        this.content = content;
    }

    public Class<?> getContentType() {
        return content.getClass();
    }
}

在上面的代碼中,我們新增了一個方法 getContentType(),該方法用于返回泛型類型參數(shù)的實際字節(jié)碼類型,以后我們通過調(diào)用這個方法,就可以間接地獲取到泛型類型的信息了。

2.3 泛型類型參數(shù)不能用于靜態(tài)變量或靜態(tài)方法

由于泛型類型參數(shù)是在實例化對象時才被確定的,因此不能在靜態(tài)變量或靜態(tài)方法中使用泛型類型參數(shù)。例如,以下代碼是無法編譯通過的:

public class MyClass<T> {   
    //這樣的代碼編譯不通過
    private static T value;   
    
    public static void setValue(T value) {        
        MyClass.value = value;     
    } 
}

正確的寫法是使用一個實際類型來代替泛型類型參數(shù):

public class MyClass {     
    private static String value;          
    public static void setValue(String value) {         
        MyClass.value = value;     
    } 
}

2.4 不能實例化T類型

比如在下面的案例中:

public class MyClass<T> {
    private T first;
    private T last;
    
    public MyClass() {
        first = new T();
        last = new T();
    }
}

上述代碼無法通過編譯,因為構(gòu)造方法的兩行語句:

first = new T(); 
last = new T(); 

擦拭后實際上變成了:

first = new Object(); 
last = new Object(); 

這樣一來,創(chuàng)建new MyClass<String>()和創(chuàng)建new MyClass<Integer>()就變成了Object,編譯器會阻止這種類型不對的代碼。如果我們想對泛型T進行實例化,需要借助Class< T >參數(shù)并集合反射技術(shù)來實現(xiàn),且在使用時也必須傳入Class< T >。


四. 結(jié)語

不過,盡管泛型擦除有一些限制,但泛型仍然不失為一種強大的編程工具,它可以提高代碼的可讀性和可維護性。通過合理地使用泛型,我們可以在編譯時進行類型檢查,避免類型轉(zhuǎn)換的錯誤和運行時異常,從而提高了代碼的安全性和可靠性。同時,我們也需要了解Java泛型擦除的限制,以便在實際應(yīng)用中做出正確的決策。

視頻教程:視頻教程,戳我直達文章來源地址http://www.zghlxwxcb.cn/news/detail-468179.html

到了這里,關(guān)于簡述泛型的基本使用和作用的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經(jīng)查實,立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費用

相關(guān)文章

  • 詳解Java中的泛型(泛型的語法,擦除機制,泛型的上界)

    詳解Java中的泛型(泛型的語法,擦除機制,泛型的上界)

    目錄 一.什么是泛型 二.Java中為什么要使用泛型 三.泛型的語法 四.泛型類的使用 五.泛型的編譯機制(擦除機制) 六.泛型的上界 泛型(Generics)是Java SE 5中引入的一個新特性,可以 使Java中的類和方法具有更廣泛的類型范圍 。通俗的說,它使得我們可以在定義類和方法時指定

    2024年02月05日
    瀏覽(24)
  • 泛型的通配符

    泛型的通配符

    類型的上界決定了泛型的范圍。 我們發(fā)現(xiàn)指定了泛型的上界為數(shù)值類Number時,傳入Boolean類型就會報錯。 如果沒有指定類型的邊界,可以認(rèn)可 T extends Object,當(dāng)指定了某個類型為上界,那么只接受某類型本身和子類型作為E的類型實參 我們要實現(xiàn)一個類去找數(shù)組的一個的最大值

    2023年04月08日
    瀏覽(21)
  • Java語言-----泛型的認(rèn)識

    Java語言-----泛型的認(rèn)識

    目錄 一.什么是泛型 二.泛型類的使用 2.1泛型類的定義 ?2.2泛型類的數(shù)組使用 三.泛型的上界? 四.泛型的方法 五.泛型與集合 ??個人主頁:?tq02的博客_CSDN博客-C語言,Java領(lǐng)域博主 ???夢的目標(biāo):努力學(xué)習(xí),向Java進發(fā),拼搏一切,讓自己的未來不會有遺憾。 ???歡迎各位→點

    2023年04月23日
    瀏覽(24)
  • Java中泛型的詳細(xì)介紹

    引言: ????????Java語言中的泛型是一種強大的特性,它允許我們在編寫代碼時指定類、接口和方法的參數(shù)類型。通過使用泛型,我們可以提高代碼的重用性、可讀性和安全性。在本博客中,我們將詳細(xì)介紹Java中泛型的知識。 ????????泛型是Java 5中引入的一個新特性。

    2024年01月18日
    瀏覽(23)
  • 對TS里泛型的理解

    概念 當(dāng)我們定義一個變量不確定類型的時候有兩種解決方式: 使用any(使用any定義時存在的問題:雖然已知道傳入值的類型但是無法獲取函數(shù)返回值的類型;另外也失去了ts類型保護的優(yōu)勢) 使用泛型(泛型指的是在定義函數(shù)/接口/類型時, 不預(yù)先指定具體的類型 ,而是

    2024年02月09日
    瀏覽(27)
  • C#(六十二)之泛型的約束

    C#(六十二)之泛型的約束

    類型約束 基類約束有兩個重要的目的。 1:它允許在泛型類中使用有約束指定的基類成員。 2:確保只能使用支持指定基類或派生類的類型實例。 約束是使用?where?上下文指定的。 下表列出了五種類型的約束: 約束 說明 T:struct 類型參數(shù)必須是值類型??梢灾付ǔ?/p>

    2024年02月17日
    瀏覽(20)
  • Java泛型的繼承和通配符

    Java泛型的繼承和通配符

    繼承 兩個容器所容納的類類型是有子類父類的關(guān)系的 但是容器之間沒有 反證法: 假設(shè)做法成立 list1=list2 list 指向list2的容器實例 list1.add(123)可以成立,明顯標(biāo)注 String 后是不行的 所以 類SuperA是類A的父類,則 GSuperA 與 GA 是并列關(guān)系沒有子父關(guān)系 類SuperA是類A的父類或接口

    2024年01月17日
    瀏覽(25)
  • 【java數(shù)據(jù)結(jié)構(gòu)】泛型的初步認(rèn)識(2)

    【java數(shù)據(jù)結(jié)構(gòu)】泛型的初步認(rèn)識(2)

    hellohello~,大家好????,這里是E綿綿呀???,如果覺得這篇文章還不錯的話還請點贊????收藏??????關(guān)注????,如果發(fā)現(xiàn)這篇文章有問題的話,歡迎各位評論留言指正,大家一起加油!一起chin up!????? ?? 個人主頁: E綿綿的博客 ?? 所屬專欄: JAVA知識點專欄

    2024年04月26日
    瀏覽(27)
  • Scala中的類型檢查和轉(zhuǎn)換,以及泛型,scala泛型的協(xié)變和逆變

    說明 (1) obj.isInstanceOf[T]:判斷 obj 是不是T 類型。 (2) obj.asInstanceOf[T]:將 obj 強轉(zhuǎn)成 T 類型。 (3) classOf 獲取對象的類名。 案例 1.說明 (1)枚舉類:需要繼承 Enumeration (2)應(yīng)用類:需要繼承App 2. 案例 1.說明 使用 type 可以定義新的數(shù)據(jù)數(shù)據(jù)類型名稱,本質(zhì)上就

    2024年02月10日
    瀏覽(23)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包