最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

一文全解Java 泛型

 更新時間:2026年05月09日 10:57:21   作者:Komore315  
文章主要介紹了Java泛型的概念、定義、使用方法及其優(yōu)勢,文章詳細(xì)介紹了泛型類、泛型方法、泛型接口以及通配符的使用方法和應(yīng)用場景,最后強調(diào)了類型擦除的概念和通配符的使用注意事項,感興趣的朋友跟隨小編一起看看吧

一、引言:

在 Java 早期版本中,集合容器默認(rèn)以Object類型存儲所有對象,無法對存入的數(shù)據(jù)類型進行約束。開發(fā)時任意類型元素都可隨意存入集合,取出元素時必須手動進行強制類型轉(zhuǎn)換,不僅代碼繁瑣冗余,還極易引發(fā)運行時類型轉(zhuǎn)換異常ClassCastException,程序類型安全性難以保障。

為解決類型不安全、強制轉(zhuǎn)換繁瑣、代碼復(fù)用性差等問題,Java 5 正式引入泛型機制。泛型允許在類、接口、方法定義時設(shè)置類型形參,在使用時再指定具體實際類型,將數(shù)據(jù)類型由運行時校驗提前到編譯期校驗。它本質(zhì)是一套類型參數(shù)化的語法模板,既能保證程序編譯期類型安全、省去手動類型強轉(zhuǎn),又能實現(xiàn)通用代碼復(fù)用,大幅提升代碼健壯性與可維護性,成為 Java 集合框架、工具類開發(fā)中不可或缺的核心特性。

也就是說:沒有泛型時,Java 集合就像一個無差別大箱子,什么類型數(shù)據(jù)都能往里扔,取出來還要自己辨別、強制轉(zhuǎn)換,容易出錯。引入泛型后,可以給箱子規(guī)定只能裝某一種類型,編譯時就限制存入類型,不用強轉(zhuǎn)、不會裝錯,還能寫出適配所有類型的通用工具類,這就是泛型設(shè)計的初衷與價值。

1.1沒有泛型(JDK5 之前寫法)

底層默認(rèn)存 Object,無類型限制、要手動強轉(zhuǎn)、容易報運行時異常

import java.util.ArrayList;
public class NoGenericDemo {
    public static void main(String[] args) {
        // 沒有泛型,集合可以隨便存任何對象
        ArrayList list = new ArrayList();
        list.add("張三");
        list.add(123);  // 故意存整數(shù),和字符串混存
        // 取值必須手動強制類型轉(zhuǎn)換
        String name = (String) list.get(0);
        System.out.println(name);
        // 運行時報錯:ClassCastException
        String num = (String) list.get(1);
    }
}

痛點

  • 能隨意存入不同類型,編譯不報錯;
  • 取值必須手動強轉(zhuǎn);
  • 類型不匹配,運行才崩潰,隱患大。

1.2有泛型

指定集合只能存 String編譯期類型檢查、無需強轉(zhuǎn)、杜絕類型混亂

import java.util.ArrayList;
public class HasGenericDemo {
    public static void main(String[] args) {
        // 泛型限定:只能存String類型
        ArrayList<String> list = new ArrayList<>();
        list.add("張三");
        // list.add(123);  // 直接編譯報錯!不讓存,從根源杜絕錯誤
        // 取值不用強制轉(zhuǎn)換,編譯器自動處理
        String name = list.get(0);
        System.out.println(name);
    }
}

優(yōu)勢

  • 編譯期就限制類型,錯誤寫代碼時就發(fā)現(xiàn);
  • 取值不用手動強轉(zhuǎn);
  • 類型安全,不會出現(xiàn) ClassCastException

二、泛型類

泛型類的定義

可以使用class名稱<泛型列表>聲明一個類,這樣的類稱之為泛型類 

例如:class people <E>

其中,people是泛型類的名稱,E是其中的泛型,也就是說并沒有指定E是何種類型的數(shù)據(jù),它可以是任何類或接口,但不能是基本數(shù)據(jù)類型。在類名后面加 <E>,E 是類型占位符,整個類都可以用 E 當(dāng)類型用,創(chuàng)建對象時再指定具體類型。

// 泛型類 <E>
class Demo<E> {
    private E num;
    public void set(E num) {
        this.num = num;
    }
    public E get() {
        return num;
    }
}
public class Test {
    public static void main(String[] args) {
        // 傳String類型
        Demo<String> d1 = new Demo<>();
        d1.set("Java");
        System.out.println(d1.get());
        // 傳Integer類型
        Demo<Integer> d2 = new Demo<>();
        d2.set(666);
        System.out.println(d2.get());
    }
}

核心特點

  • MyBox<E>泛型類,<E> 聲明類型占位符;
  • 同一個類,可以復(fù)用給 String、Integer、自定義對象;
  • 編譯期類型約束,存錯類型直接報錯;
  • 取值不用強制類型轉(zhuǎn)換

三、泛型方法

和普通的類相比,泛型類聲明和創(chuàng)建對象時,類名后多了一對<>,而且要用具體的類型替換<>中的泛型(或使用統(tǒng)配“?”)

1.使用具體類型

格式:泛型類<具體類型> 變量名 = new 泛型類<>(構(gòu)造參數(shù));

用具體類型替換<>中的泛型,例如,用具體類型circle替換泛型E

Circle circle =new Circle();
Cone<Circle>coneOne;//用具體類型Circle,不可以用泛型E:cone<E>coneOne;
coneOne=new Cone<Circle>(circle);
  • Cone<E> 是一個泛型類,E 是類型參數(shù)。
  • 聲明變量時,Cone<Circle> 表示:這個 coneOne 只能存 Circle 類型的對象。
  • 不能寫 Cone<E> coneOne;,因為 E 只是類定義里的占位符,創(chuàng)建對象時必須用具體類型替換它。
  • 創(chuàng)建對象時,new Cone<Circle> 后面的類型,要和前面聲明的類型一致(JDK7+ 也可以寫成 new Cone<>(circle),編譯器會自動推斷)。

2.使用統(tǒng)配“?”

  • 無界通配符:Cone<?> cone,表示任意類型的 Cone,等價于 Cone<? extends Object>。
  • 上界通配符:Cone<? extends Geometry> cone
    • 含義:只能接收類型為 Cone<Geometry>Cone<Geometry子類> 的對象。
    • 限制:只能讀、不能寫(編譯器不知道具體子類型,禁止寫入)。
  • 下界通配符:Cone<? super Geometry> cone
    • 含義:只能接收類型為 Cone<Geometry>Cone<Geometry父類> 的對象。
    • 限制:只能寫、讀時只能拿到 Object。

基礎(chǔ)類:

// 父類
class Geometry{}
// 子類
class Circle extends Geometry{}
// 泛型類
class Cone<E>{
    private E e;
    public Cone(E e){ this.e = e; }
    // 設(shè)值
    public void set(E e){ this.e = e; }
    // 取值
    public E get(){ return e; }
}

無界通配符 Cone<?>

// 可以接收任何類型
Cone<?> c1 = new Cone<>(new Circle());
Cone<?> c2 = new Cone<>(new Geometry());
// ? 可以讀,只能拿到 Object
Object obj = c1.get();
// ? 不能寫入任何數(shù)據(jù)
// c1.set(new Circle()); 編譯報錯

上界通配符 Cone<? extends Geometry>

// 合法:本身、子類都可以
Cone<? extends Geometry> cone = new Cone<>(new Circle());
// ? 可讀,讀到的是 Geometry
Geometry g = cone.get();
// ? 不能往里存任何對象
// cone.set(new Circle()); 編譯報錯

下界通配符 Cone<? super Geometry>

// 合法:Geometry、父類Object都行
Cone<? super Geometry> cone = new Cone<>(new Geometry());
// ? 可以寫入子類對象
cone.set(new Circle());
// ? 能讀,但只能用 Object 接收
Object obj = cone.get();
// ? 不能用 Geometry 接收
// Geometry g = cone.get(); 編譯報錯
  • ? 無界:隨便收,只能讀
  • ? extends 父類 上界:收子類,只能讀
  • ? super 子類 下界:收父類,可以寫

泛型類聲明對象時可以用通配符“?”來限制泛型的范圍。

Cone<? extends Geometry>coneOne

如果 Geometry 類是類,那么 “<? extends Geometry>” 中的 “? extends Geometry” 表示任何 Geometry 類的子類或 Geometry 類本身(可理解為泛型 E 被限制了范圍);如果 Geometry 是接口,那么 “<? extends Geometry>” 中的 “? extends Geometry” 表示任何實現(xiàn) Geometry 接口的類。

這里的 ? extends Geometry 叫上界通配符,作用是:

  • 限制 Cone 里的類型,必須是 Geometry 本身,或者它的子類(如果 Geometry 是接口,就是實現(xiàn)它的類)。
  • 注意:? 不是類型變量,只是 “未知類型” 的占位符,不能用它定義泛型類,只能用在聲明變量、方法參數(shù)上。

四、泛型接口

可以使用interface名稱<泛型列表>聲明一個接口,這樣聲明的接口稱作泛型接口

1、泛型接口定義格式

// 接口后加 <E> 泛型標(biāo)識
public interface 接口名<E> {
    E get();
    void set(E e);
}

本質(zhì):和泛型類一樣,把類型做成參數(shù),讓接口方法的參數(shù)、返回值統(tǒng)一由泛型約束。

2、泛型接口兩種實現(xiàn)方式

方式 1:實現(xiàn)類明確指定泛型具體類型

// 1. 定義泛型接口
interface MyInterface<E> {
    void show(E e);
}
// 2. 實現(xiàn)類直接寫死類型:固定為 String
class Impl implements MyInterface<String> {
    @Override
    public void show(String s) {
        System.out.println(s);
    }
}
Impl impl = new Impl();
impl.show("泛型接口測試");

特點:實現(xiàn)類類型固定,只能用一種類型。

方式 2:實現(xiàn)類也定義為泛型類,保留泛型<E>

// 泛型接口
interface MyInterface<E> {
    void show(E e);
}
// 實現(xiàn)類也帶泛型,不指定具體類型
class Impl<E> implements MyInterface<E> {
    @Override
    public void show(E e) {
        System.out.println(e);
    }
}
Impl<String> i1 = new Impl<>();
i1.show("張三");
Impl<Integer> i2 = new Impl<>();
i2.show(666);

特點:實現(xiàn)類也是泛型,一套實現(xiàn)適配多種類型。

3、泛型接口核心

  • 定義格式接口名后跟 <E>,接口中抽象方法可以用 E 作參數(shù) / 返回值。
  • 兩種實現(xiàn)方式
    • 實現(xiàn)類指定具體類型:實現(xiàn)類類型固定;
    • 實現(xiàn)類保留泛型<E>:實現(xiàn)類也是泛型,可復(fù)用。
  • 泛型接口也能加邊界限制
// 限制E只能是Geometry或子類
interface MyInterface<E extends Geometry> {
    E get();
}
  • 多泛型接口可以同時定義多個泛型:
interface I<K,V> {
    K getKey();
    V getValue();
}
  • 特點總結(jié)
  • 接口抽象方法的參數(shù)、返回值可以由泛型統(tǒng)一約束;
  • 兼顧接口規(guī)范 + 泛型類型安全、代碼復(fù)用
  • 集合里 Iterable<E>、Collection<E>、List<E> 全是泛型接口。

五、類型擦除

假如我們定義了一個 ArrayList< Integer > 泛型集合,若向該集合中插入 String 類型的對象,不需要運行程序,編譯器就會直接報錯。這里可能有小伙伴就產(chǎn)生了疑問:

不是說泛型信息在編譯的時候就會被擦除掉嗎?那既然泛型信息被擦除了,如何保證我們在集合中只添加指定的數(shù)據(jù)類型的對象呢?

換而言之,我們雖然定義了 ArrayList< Integer > 泛型集合,但其泛型信息最終被擦除后就變成了 ArrayList< Object > 集合,那為什么不允許向其中插入 String 對象呢?

Java 是如何解決這個問題的?

其實在創(chuàng)建一個泛型類的對象時, Java 編譯器是先檢查代碼中傳入 < T > 的數(shù)據(jù)類型,并記錄下來,然后再對代碼進行編譯,編譯的同時進行類型擦除;如果需要對被擦除了泛型信息的對象進行操作,編譯器會自動將對象進行類型轉(zhuǎn)換。

1. 什么是類型擦除定義

泛型只在編譯階段有效,編譯通過后,進入運行階段時,JVM 會把代碼中所有泛型標(biāo)識 <E>、<String>、<Integer> 全部抹掉,變回原始類型 Object(或指定上界類型),這個過程就叫類型擦除 。

通俗理解

  • 編譯時:泛型是給編譯器看的,做類型檢查、約束類型;
  • 運行時:JVM 不認(rèn)識泛型,把所有泛型標(biāo)記全部擦掉,變回普通類、普通集合。

編譯寫的:

ArrayList<String> list = new ArrayList<>();

編譯后字節(jié)碼里等價于:

ArrayList list = new ArrayList();

泛型 <String> 被擦除消失了。

2. 類型擦除的原理(底層機制)

核心原理三步

  • 第一步:編譯期語法檢查編譯器根據(jù)泛型 <E> 約束:
    • 只能存指定類型;
    • 報錯類型不匹配的代碼;
    • 自動幫你補上隱式強制類型轉(zhuǎn)換。
  • 第二步:擦除泛型參數(shù)
    • 無邊界泛型 <E> → 直接擦除為 Object
    • 有邊界泛型 <E extends 父類> → 擦除為 父類類型

示例:

  • class Box<E> ?? 擦除為 class Box<Object>
  • class Box<E extends Geometry> ?? 擦除為 class Box<Geometry>
  • 第三步:運行時只剩原始類型運行時:
  • ArrayList<String>ArrayList<Integer> 本質(zhì)是同一個 ArrayList 類
  • 不會因為泛型不同,生成新的類字節(jié)碼
  • 泛型僅僅是編譯期語法糖,運行無泛型

3.關(guān)鍵結(jié)論

  • 泛型是編譯期概念,運行不存在泛型;
  • 類型擦除后,泛型類型變回 Object 或其上界父類;
  • List<String>List<Integer> 運行時是同一個類型;
  • 為什么不能用 instanceof 判斷泛型?因為運行時泛型已經(jīng)被擦掉了,識別不了具體泛型類型。

六、泛型通配符

1、什么是泛型通配符?

泛型通配符用 ? 表示,是一種「不確定的泛型類型占位符」,核心用途是:

  • 接收未知的泛型類型,適配多種泛型場景
  • 限制泛型類型的范圍,保證類型安全

關(guān)鍵注意:通配符 ? 只能用在「變量聲明」「方法參數(shù)」上,不能用來定義泛型類、泛型接口(比如 class A<?> {} 是錯誤寫法)。

2、三種泛型通配符

泛型通配符分為三種,核心區(qū)別在于「類型范圍限制」和「讀寫權(quán)限」,我們結(jié)合代碼示例逐一講解(以下示例均基于父類Geometry、子類 Circle 和泛型類 Cone<E> 演示)。

基礎(chǔ)準(zhǔn)備(所有示例共用)

// 父類
class Geometry {} 
// 子類 
class Circle extends Geometry {} 
// 泛型類 
class Cone<E> {
 private E element; public Cone(E element) {
 this.element = element; } 
public void set(E element) { 
this.element = element; } 
// 寫操作 
public E get() {
 return element; } // 讀操作 
}

1. 無界通配符 | ?

含義:無任何類型限制,可以接收「任意泛型類型」,等價于 ? extends Object。

核心特點:只能讀,不能寫(無法確定具體類型,為保證安全,禁止添加任何元素)。

// 無界通配符:可接收任意類型的 Cone 
Cone<?> cone1 = new Cone<>(new Circle()); 
Cone<?> cone2 = new Cone<>("測試"); 
Cone<?> cone3 = new Cone<>(123); // ? 可讀:讀取結(jié)果統(tǒng)一為 Object 類型 
Object obj = cone1.get(); 
// ? 不可寫:無論添加什么類型,都會編譯報錯 
// cone1.set(new Circle()); 
// cone1.set("abc");

2. 上界通配符 | ? extends 上限類

含義:限制泛型類型必須是「上限類本身,或上限類的子類」(本文以上限類 Geometry 為例)。

核心特點:只能讀,不能寫(編譯器無法確定具體是哪種子類,禁止添加元素,避免類型混亂)。

// 上界通配符:只能接收 Cone<Geometry> 或 Cone<Circle>(子類) 
Cone<? extends Geometry> cone = new Cone<>(new Circle()); 
// ? 可讀:讀取結(jié)果為上限類 Geometry 類型(無需強轉(zhuǎn)) 
Geometry g = cone.get(); 
// ? 不可寫:即使添加子類 Circle,也會編譯報錯 
// cone.set(new Circle()); 
// cone.set(new Geometry());

3. 下界通配符 | ? super 下限類

含義:限制泛型類型必須是「下限類本身,或下限類的父類」(本文以下限類 Geometry 為例)。

核心特點:可以寫(只能添加下限類的子類元素),讀取時只能拿到 Object 類型(無法確定具體父類類型)。

// 下界通配符:只能接收 Cone<Geometry> 或 Cone<Object>(父類) 
Cone<? super Geometry> cone = new Cone<>(new Geometry()); 
// ? 可寫:只能添加下限類的子類(Circle 是 Geometry 的子類) 
cone.set(new Circle()); 
// ? 可讀:只能用 Object 接收,無法直接用 Geometry 接收 
Object obj = cone.get(); 
// ? 錯誤寫法:不能用 Geometry 接收讀取結(jié)果 
// Geometry g = cone.get();

3、超強記憶口訣

1. 無界通配符 ?:隨便收,只能讀

2. 上界通配符 ? extends:只出不進(只讀不寫)

3. 下界通配符 ? super:只進不出(可寫,讀只能拿 Object)

4、高頻避坑指南

避坑1:通配符不能定義泛型類/接口

// ? 錯誤:不能用 ? 定義泛型類 public class Cone<?> {}

正確寫法:用泛型標(biāo)識(E、T、K 等)定義,通配符只用于使用時。

避坑2:泛型無繼承性,需用通配符兼容

即使CircleGeometry 的子類,Cone<Circle>不是Cone<Geometry> 的子類,直接賦值會報錯:

// ? 錯誤:泛型無繼承性 
Cone<Geometry> cone = new Cone<>(new Circle()); 
// ? 正確:用上界通配符兼容 
Cone<? extends Geometry> cone = new Cone<>(new Circle());

避坑3:運行時泛型擦除,通配符也會被擦除

運行時,JVM 不認(rèn)識泛型和通配符,所有泛型標(biāo)識(包括 ?)都會被擦除,變回原始類型(Object 或上界類)。因此,無法用 instanceof 判斷泛型類型:

// ? 錯誤:編譯報錯,無法判斷泛型類型 
if (cone instanceof Cone<Circle>) {}

5、總結(jié)

泛型通配符的核心是「不確定類型的占位」,三種通配符的核心區(qū)別在于「類型范圍」和「讀寫權(quán)限」:

  • 無界 ?:適配所有類型,只讀
  • 上界 ? extends:限制子類范圍,只讀
  • 下界 ? super:限制父類范圍,可寫(子類)、讀Object

實際開發(fā)中,上界通配符常用于「讀取數(shù)據(jù)」(比如遍歷集合),下界通配符常用于「寫入數(shù)據(jù)」(比如往集合中添加元素),掌握這個核心場景,就能靈活運用通配符啦

到此這篇關(guān)于一文全解Java 泛型的文章就介紹到這了,更多相關(guān)java 泛型內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • java中switch條件語句的三種語法、用法及支持的參數(shù)類型

    java中switch條件語句的三種語法、用法及支持的參數(shù)類型

    Java中的switch語句是一種多分支選擇結(jié)構(gòu),可以一個變量的值改變程序的控制流,這篇文章主要給大家介紹了關(guān)于java中switch條件語句的三種語法、用法及支持的參數(shù)類型的相關(guān)資料,需要的朋友可以參考下
    2024-06-06
  • java中利用Dom4j解析和生成XML文檔

    java中利用Dom4j解析和生成XML文檔

    本篇文章主要介紹了java中利用Dom4j解析和生成XML文檔,dom4j是一套非常優(yōu)秀的Java開源api,主要用于讀寫xml文檔,具有性能優(yōu)異、功能強大、和非常方便使用的特點。有興趣的可以了解一下。
    2016-11-11
  • Java并發(fā)多線程編程之CountDownLatch的用法

    Java并發(fā)多線程編程之CountDownLatch的用法

    這篇文章主要介紹了Java并發(fā)多線程編程之CountDownLatch的用法,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-06-06
  • Java連接MongoDB的常用方法詳解

    Java連接MongoDB的常用方法詳解

    這篇文章主要為大家詳細(xì)介紹一下Java語言連接MongoDB的常用方法以及實現(xiàn)增刪改查功能的示例代碼,感興趣的小伙伴可以跟隨小編一起了解一下
    2022-07-07
  • java開發(fā)環(huán)境的完整搭建過程

    java開發(fā)環(huán)境的完整搭建過程

    這篇文章主要給大家介紹了關(guān)于java開發(fā)環(huán)境的完整搭建過程,文中介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-02-02
  • 詳解JUC并發(fā)編程之鎖

    詳解JUC并發(fā)編程之鎖

    這篇文章主要為大家介紹了JUC并發(fā)編程之鎖,具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2021-12-12
  • 一文吃透Spring?Cloud?gateway自定義錯誤處理Handler

    一文吃透Spring?Cloud?gateway自定義錯誤處理Handler

    這篇文章主要為大家介紹了一文吃透Spring?Cloud?gateway自定義錯誤處理Handler方法,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-03-03
  • 淺談sql_@SelectProvider及使用注意說明

    淺談sql_@SelectProvider及使用注意說明

    這篇文章主要介紹了sql_@SelectProvider及使用注意說明,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-08-08
  • SpringBoot最常用的50個注解總結(jié)(全是干貨!)

    SpringBoot最常用的50個注解總結(jié)(全是干貨!)

    SpringBoot提供多種注解簡化配置與啟動流程,如@SpringBootAppication、@RestController、@RequestMapping等,這篇文章主要介紹了SpringBoot最常用的50個注解的相關(guān)資料,需要的朋友可以參考下
    2024-09-09
  • Spring Boot加密配置文件特殊內(nèi)容的示例代碼詳解

    Spring Boot加密配置文件特殊內(nèi)容的示例代碼詳解

    這篇文章主要介紹了Spring Boot加密配置文件特殊內(nèi)容的相關(guān)知識,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-05-05

最新評論

庄河市| 武胜县| 秦皇岛市| 辰溪县| 纳雍县| 合水县| 明光市| 黎城县| 温宿县| 宜宾市| 西盟| 长沙县| 锦州市| 印江| 鸡西市| 富川| 申扎县| 赤城县| 盘山县| 迁安市| 华蓥市| 福鼎市| 平乡县| 泽库县| 罗山县| 枣强县| 理塘县| 虎林市| 恩平市| 泽州县| 阜新| 惠州市| 澎湖县| 壤塘县| 象州县| 固镇县| 双江| 拜泉县| 瓦房店市| 通河县| 上思县|