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

Java 泛型通配符 <? extends> vs <? super> 實(shí)戰(zhàn)場(chǎng)景

 更新時(shí)間:2025年12月23日 11:54:59   作者:嗯嗯嗯吧  
本文解析Java泛型通配符<? extends T>和<? super T>的核心區(qū)別與應(yīng)用場(chǎng)景,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

一、引言

泛型通配符是 Java 泛型的核心特性,但其<? extends><? super>的用法常讓開發(fā)者混淆 —— 用錯(cuò)會(huì)導(dǎo)致編譯報(bào)錯(cuò)(如 “無法添加元素”“類型轉(zhuǎn)換異常”),或隱藏邏輯隱患。實(shí)際開發(fā)中,集合傳參、工具類設(shè)計(jì)、框架 API 調(diào)用都離不開這兩個(gè)通配符。本文基于 Java 17+,通過 “原理拆解 + 實(shí)戰(zhàn)場(chǎng)景” 講清兩者差異,幫你快速掌握 “什么時(shí)候用 extends,什么時(shí)候用 super”。

二、核心知識(shí)點(diǎn)解析

1. 泛型通配符基礎(chǔ)概念

泛型通配符(Wildcard):用?表示未知的泛型類型,用于限制泛型的取值范圍,增強(qiáng)代碼靈活性(Java 5 引入,Java 17 + 優(yōu)化了編譯時(shí)類型檢查精度)。

  • <? extends T>:上界通配符,限制泛型類型 “必須是 T 或 T 的子類”(如<? extends Number>可匹配Integer、DoubleNumber);
  • <? super T>:下界通配符,限制泛型類型 “必須是 T 或 T 的父類”(如<? super Integer>可匹配Integer、Number、Object)。

2. 核心原則:PECS 法則(Producer Extends, Consumer Super)

這是區(qū)分兩者的關(guān)鍵法則,由 Java 官方推薦:

  • Producer(生產(chǎn)者):僅提供數(shù)據(jù)(取元素),不接收數(shù)據(jù)(存元素)→ 用<? extends T>;例:從集合中讀取數(shù)據(jù)統(tǒng)計(jì)總和,集合是 “數(shù)據(jù)生產(chǎn)者”;
  • Consumer(消費(fèi)者):僅接收數(shù)據(jù)(存元素),不提供數(shù)據(jù)(或僅取 Object 類型數(shù)據(jù))→ 用<? super T>;例:向集合中添加數(shù)據(jù),集合是 “數(shù)據(jù)消費(fèi)者”。

3. 讀寫權(quán)限差異(Java 17 + 編譯檢查)

通配符類型讀取數(shù)據(jù)(取)寫入數(shù)據(jù)(存)
<? extends T>可讀取為 T 類型(安全)禁止寫入(除 null 外),編譯報(bào)錯(cuò)
<? super T>僅可讀取為 Object 類型(不安全)可寫入 T 或 T 的子類(安全)

三、實(shí)戰(zhàn)案例

場(chǎng)景 1:基礎(chǔ)場(chǎng)景 —— 集合讀寫操作對(duì)比(Java 17+)

示例 1:<? extends>讀取數(shù)據(jù)(生產(chǎn)者場(chǎng)景)

// Java 17+支持
import java.util.ArrayList;
import java.util.List;
 
public class ExtendsDemo {
    // 統(tǒng)計(jì)數(shù)字集合的總和(僅讀取,生產(chǎn)者)
    public static double sum(List<? extends Number> numberList) {
        double total = 0.0;
        for (Number num : numberList) {
            total += num.doubleValue(); // 讀取為Number類型,安全
        }
        // numberList.add(10); // 編譯報(bào)錯(cuò):<? extends Number> 禁止添加元素
        return total;
    }
 
    public static void main(String[] args) {
        List<Integer> intList = new ArrayList<>();
        intList.add(10);
        intList.add(20);
        
        List<Double> doubleList = new ArrayList<>();
        doubleList.add(3.14);
        doubleList.add(6.28);
        
        // 支持Integer、Double等Number子類集合
        //http://fycj.tm66d.cn 
        System.out.println("整數(shù)列表總和:" + sum(intList)); // 輸出30.0
        System.out.println("小數(shù)列表總和:" + sum(doubleList)); // 輸出9.42
    }
 
}

示例 2:<? super>寫入數(shù)據(jù)(消費(fèi)者場(chǎng)景)

// Java 17+支持
import java.util.ArrayList;
import java.util.List;
 
public class SuperDemo {
    // 向集合中添加整數(shù)(僅寫入,消費(fèi)者)
    public static void addIntegers(List<? super Integer> integerList) {
        integerList.add(10); // 可添加Integer類型
        integerList.add(20); // 可添加Integer子類(此處無子類,直接加Integer)
        // integerList.add(3.14); // 編譯報(bào)錯(cuò):Double不是Integer的子類
        
        // 讀取時(shí)僅能轉(zhuǎn)為Object
        for (Object obj : integerList) {
            System.out.println("元素:" + obj);
        }
    }
 
    public static void main(String[] args) {
        List<Integer> intList = new ArrayList<>();
        List<Number> numberList = new ArrayList<>();
        List<Object> objList = new ArrayList<>();
        
        // 支持Integer、Number、Object等父類集合
        addIntegers(intList); // 輸出:10、20
        addIntegers(numberList); // 輸出:10、20
        addIntegers(objList); // 輸出:10、20
    }
}

場(chǎng)景 2:進(jìn)階場(chǎng)景 —— 框架工具類設(shè)計(jì)(模擬 Collections.addAll)

Java 17 + 的Collections.addAll方法底層使用<? super T>,支持向父類集合添加子類元素,我們模擬其核心邏輯:

// Java 17+支持
import java.util.Collection;
import java.util.List;
 
public class CollectionUtils {
    /**
     * 批量添加元素到集合(消費(fèi)者場(chǎng)景,用<? super T>)
     * @param dest 目標(biāo)集合(接收元素)
     * @param elements 待添加元素(T或T的子類)
     */
    @SafeVarargs
    public static <T> boolean addAll(Collection<? super T> dest, T... elements) {
        boolean modified = false;
        for (T elem : elements) {
            modified |= dest.add(elem); // 寫入安全,編譯通過
        }
        return modified;
    }
 
    public static void main(String[] args) {
        List<Number> numberList = new ArrayList<>();
        Integer[] ints = {1, 2, 3};
        Double[] doubles = {4.0, 5.0};
        
        // 向Number集合添加Integer、Double(Number的子類)
        addAll(numberList, ints); 
        addAll(numberList, doubles);
        
        System.out.println(numberList); // 輸出:[1, 2, 3, 4.0, 5.0]
    }
}

場(chǎng)景 3:綜合場(chǎng)景 —— 泛型方法的讀寫結(jié)合

// Java 17+支持
import java.util.List;
 
public class GenericCombinationDemo {
    /**
     * 從源集合讀取數(shù)據(jù)(extends),寫入目標(biāo)集合(super)
     * @param source 源集合(生產(chǎn)者)
     * @param dest 目標(biāo)集合(消費(fèi)者)
     */
    public static <T> void copy(List<? extends T> source, List<? super T> dest) {
        for (T elem : source) {
            dest.add(elem); // 源集合取T類型,目標(biāo)集合存T類型,雙向安全
        }
    }
 
    public static void main(String[] args) {
        List<Integer> intSource = List.of(1, 2, 3); // Java 9+ List.of(),Java 17+兼容
        List<Number> numberDest = new ArrayList<>();
        List<Object> objDest = new ArrayList<>();
        
        // 從Integer集合復(fù)制到Number、Object集合
        copy(intSource, numberDest);
        copy(intSource, objDest);
        
        System.out.println(numberDest); // 輸出:[1, 2, 3]
        System.out.println(objDest); // 輸出:[1, 2, 3]
    }
}

四、易錯(cuò)點(diǎn)與避坑指南

易錯(cuò)點(diǎn) 1:用<? extends T>嘗試添加元素

錯(cuò)誤代碼

List<? extends Number> list = new ArrayList<Integer>();
list.add(10); // 編譯報(bào)錯(cuò):The method add(capture#1-of ? extends Number) is undefined for the type List<capture#1-of ? extends Number>

正確代碼

List<Number> list = new ArrayList<Integer>(); // 直接用具體類型接收,或用<? super T>
list.add(10);

原因分析<? extends Number> 可能是List<Integer>List<Double>,若允許添加Integer,當(dāng)集合實(shí)際是List<Double>時(shí)會(huì)導(dǎo)致類型不匹配,Java 17 + 編譯時(shí)直接禁止該操作(除list.add(null)外,null 是所有類型的實(shí)例)。

易錯(cuò)點(diǎn) 2:用<? super T>讀取數(shù)據(jù)并強(qiáng)轉(zhuǎn)

錯(cuò)誤代碼

List<? super Integer> list = new ArrayList<Number>();
list.add(10);
Integer num = (Integer) list.get(0); // 編譯警告,運(yùn)行時(shí)可能報(bào)錯(cuò)

正確代碼

List<? super Integer> list = new ArrayList<Number>();
list.add(10);
Object obj = list.get(0); // 僅能安全轉(zhuǎn)為Object
if (obj instanceof Integer) {
    Integer num = (Integer) obj; // 加類型判斷,避免強(qiáng)轉(zhuǎn)異常
}

原因分析<? super Integer> 可能是List<Number>List<Object>get(0)返回的是Object類型,直接強(qiáng)轉(zhuǎn)Integer可能因集合中存在其他類型元素(如Double)導(dǎo)致ClassCastException

易錯(cuò)點(diǎn) 3:過度使用通配符,降低代碼可讀性

錯(cuò)誤代碼

// 無需通配符,直接用具體泛型即可
public static void process(List<? extends Object> list) {
    // 邏輯...
}

正確代碼

public static void process(List<Object> list) {
    // 邏輯...
}

原因分析<? extends Object> 等價(jià)于?,但語義不清晰,且無法添加任何非 null 元素;若業(yè)務(wù)允許所有類型,直接用List<Object>更直觀,且支持添加任意元素。

易錯(cuò)點(diǎn) 4:泛型數(shù)組與通配符混用錯(cuò)誤

錯(cuò)誤代碼

List<? extends Number>[] arr = new List<Integer>[10]; 
// 編譯報(bào)錯(cuò):Generic array creation 

正確代碼

List<? extends Number>[] arr = new List[10]; // 用原始類型數(shù)組(不推薦)
// 或優(yōu)先用集合替代數(shù)組:
List<List<? extends Number>> list = new ArrayList<>();

原因分析:Java 不允許創(chuàng)建泛型數(shù)組(如List<Integer>[]),通配符泛型數(shù)組也不例外,避免數(shù)組協(xié)變導(dǎo)致的類型安全問題(Java 17 + 仍嚴(yán)格限制該語法)。

易錯(cuò)點(diǎn) 5:方法返回值使用通配符

錯(cuò)誤代碼

// 返回值用通配符,調(diào)用方需額外處理類型,體驗(yàn)差
public static List<? extends Number> createList() {
    return new ArrayList<Integer>();
}

正確代碼

// 直接返回具體泛型類型,或用泛型方法
public static List<Integer> createList() {
    return new ArrayList<Integer>();
}
// 或支持多種類型:
public static <T extends Number> List<T> createList(Class<T> clazz) {
    return new ArrayList<>();
}

原因分析:返回值用通配符會(huì)增加調(diào)用方的使用成本(需強(qiáng)制類型轉(zhuǎn)換或類型判斷),且無法充分利用泛型的類型安全特性,除非確需返回多種不確定類型,否則優(yōu)先用具體泛型或泛型方法。

五、總結(jié)與擴(kuò)展

本文核心是掌握 PECS 法則:生產(chǎn)者用<? extends T>(讀數(shù)據(jù)),消費(fèi)者用<? super T>(寫數(shù)據(jù)),讀寫結(jié)合時(shí)兩者搭配使用。Java 17 + 對(duì)泛型通配符的編譯檢查更嚴(yán)格,能提前規(guī)避多數(shù)類型錯(cuò)誤。擴(kuò)展方向:1. 學(xué)習(xí)泛型上限(<T extends Number>)與上界通配符的區(qū)別;2. 研究 Java 21 新特性 “泛型模式匹配” 對(duì)通配符的優(yōu)化;3. 分析 Spring、MyBatis 等框架中通配符的應(yīng)用場(chǎng)景(如ParameterizedType處理)。

面試高頻提問

  1. 泛型通配符<? extends><? super>的核心區(qū)別是什么?PECS 法則的含義?
  2. 為什么<? extends T>不能添加元素,而<? super T>可以?
  3. 方法參數(shù)用List<T>List<? extends T>有什么區(qū)別?
  4. 如何安全地從<? super T>集合中讀取T類型元素?

到此這篇關(guān)于Java 泛型通配符 <? extends> vs <? super> 實(shí)戰(zhàn)場(chǎng)景的文章就介紹到這了,更多相關(guān)Java 泛型通配符 內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Maven版本管理之SNAPSHOT,Release與Nexus倉庫的區(qū)別和影響詳解

    Maven版本管理之SNAPSHOT,Release與Nexus倉庫的區(qū)別和影響詳解

    在?Java?Maven?項(xiàng)目中,我們經(jīng)常會(huì)看到不同形式的版本號(hào),這些版本號(hào)看起來差別不大,但在?Maven?構(gòu)建、依賴管理和生產(chǎn)環(huán)境穩(wěn)定性方面,影響非常明顯,下面小編就和大家詳細(xì)講解一下吧
    2026-05-05
  • 一個(gè)簡(jiǎn)單的類加載器URLClassLoader案例

    一個(gè)簡(jiǎn)單的類加載器URLClassLoader案例

    這篇文章主要介紹了一個(gè)簡(jiǎn)單的類加載器URLClassLoader案例,這里寫了一個(gè)小 demo,來加深對(duì)于反射的理解,需要的朋友可以參考下
    2023-04-04
  • java?log?is判斷引發(fā)的一系列事件解析

    java?log?is判斷引發(fā)的一系列事件解析

    這篇文章主要為大家介紹了java?log?is判斷引發(fā)的一系列事件解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-11-11
  • spring-boot報(bào)錯(cuò)java: 程序包javax.servlet.http不存在

    spring-boot報(bào)錯(cuò)java: 程序包javax.servlet.http不存在

    當(dāng)springboot項(xiàng)目從2.7.x的升級(jí)到3.0.x的時(shí)候,會(huì)遇到一個(gè)問題java: 程序包javax.servlet.http不存在,下面就來具體介紹一下,感興趣的可以了解一下
    2024-08-08
  • 關(guān)于MVC設(shè)計(jì)模式及流程解析

    關(guān)于MVC設(shè)計(jì)模式及流程解析

    這篇文章主要介紹了關(guān)于MVC設(shè)計(jì)模式及流程解析,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-05-05
  • ArrayList及HashMap的擴(kuò)容規(guī)則講解

    ArrayList及HashMap的擴(kuò)容規(guī)則講解

    今天小編就為大家分享一篇關(guān)于ArrayList及HashMap的擴(kuò)容規(guī)則講解,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧
    2019-02-02
  • 深入分析JAVA Synchronized關(guān)鍵字

    深入分析JAVA Synchronized關(guān)鍵字

    這篇文章主要介紹了析JAVA Synchronized關(guān)鍵字的相關(guān)知識(shí),文中代碼非常詳細(xì),幫助大家更好的理解和學(xué)習(xí),感興趣的朋友可以了解下
    2020-06-06
  • windows系統(tǒng)配置Java開發(fā)環(huán)境變量

    windows系統(tǒng)配置Java開發(fā)環(huán)境變量

    這篇文章主要介紹了windows系統(tǒng)配置Java開發(fā)環(huán)境變量,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2021-12-12
  • Java線程局部變量ThreadLocal的核心原理與正確實(shí)踐指南

    Java線程局部變量ThreadLocal的核心原理與正確實(shí)踐指南

    ThreadLocal是一個(gè)強(qiáng)大而精巧的工具,它通過線程隔離數(shù)據(jù)的方式,優(yōu)雅地解決了特定場(chǎng)景下的線程安全問題,本文給大家介紹Java線程局部變量ThreadLocal的核心原理與正確實(shí)踐指南,感興趣的朋友跟隨小編一起看看吧
    2025-11-11
  • Java面試題沖刺第九天--MyBatis

    Java面試題沖刺第九天--MyBatis

    這篇文章主要為大家分享了最有價(jià)值的三道MyBatis框架面試題,涵蓋內(nèi)容全面,包括數(shù)據(jù)結(jié)構(gòu)和算法相關(guān)的題目、經(jīng)典面試編程題等,感興趣的小伙伴們可以參考一下
    2021-07-07

最新評(píng)論

呼玛县| 黎川县| 威信县| 汨罗市| 佛冈县| 恩平市| 贵溪市| 喜德县| 安吉县| 财经| 长武县| 广水市| 池州市| 荔浦县| 建昌县| 海阳市| 吉首市| 青龙| 锡林郭勒盟| 磴口县| 东平县| 库尔勒市| 华坪县| 延边| 津南区| 酉阳| 监利县| 左贡县| 兴海县| 隆尧县| 上饶市| 漳平市| 和平县| 民权县| 绥棱县| 疏附县| 浮山县| 聂荣县| 甘洛县| 丰原市| 灵丘县|