【Java】泛型在 Java 中是怎樣實現的?

先說結論 , Java 的泛型是偽泛型 , 在運行期間不存在泛型的概念 , 泛型在 Java 中是 編譯檢查 + 運行強轉 實現的

泛型是指 允許在定義類 , 接口和方法時使用的類型參數 , 使得代碼可以在不指定具體類型的情況下操作不同的數據類型 , 從而實現類型安全的代碼復用 的語言機制 .

集合框架和內置函數式接口等內容都使用了泛型 .

通配符

<>泛型類型參數列表 , 可以包含多個參數 .

?通配符 , 可以配合 extends 和 super 關鍵字表示不明類型的上下限 .

<T> 通常用于泛型類源碼聲明 , T 作為占位符表示實例化的泛型參數 .

<?> 可以用在實例化上 , 此時泛型參數不明確 , 通常不能寫入變量 .

不能 Box<?> box = new Box<?>(); , 但可以聲明 Box<?> box = new Box<String>(); , 這樣只能安全讀取 Object 元素 , 不能寫入任何非 null 元素 . new 語句右側的 <> 叫做鉆石操作符 , 鉆石操作符的作用是讓編譯器根據左側泛型參數推斷右側的實際參數 . 如果左側是 <?> 參數不明 , 那么右側則必須顯式指定泛型參數 .

通配符寫法作用允許讀取允許寫入
<?>任意類型可以讀取為 Object只能寫入 null
<? extends T>T 或其子類型(上界)可以讀取為 T不能寫入具體元素
<? super T>T 或其父類型(下界)只能讀取為 Object可以寫入 T 或子類型

生產消費原則 ( PECS )

Producer Extends, Consumer Super .

  • 生產者使用 <? extends T> 上界通配符 : 只能讀 , 不能寫 .
List<? extends Number> list = new ArrayList<Integer>();

list 是 Number 或其子類類型的集合 , 可以安全地將集合元素當作 Number 讀取 , 因為確定是 Number 及其子類 .

只能確定泛型參數的上界 , 實際類型不確定 , 所以不允許寫入 .

  • 消費者使用 <? super T> 下界通配符 : 只能寫 , 讀不明白 .
List<? super Integer> list = new ArrayList<Number>();

list 是 Integer 或其父類類型的集合 , 因為 Java 向下轉型是安全的 , 所以可以將 Integer 或其子類放入集合 , 因為集合元素類型一定是 Integer 或其父類 .

因為只能確定泛型參數的下界 , 所以編譯期將 ? super Integer 擦除成 Object , 且讀取時只能保證元素是 Object .

類型擦除

編譯器將泛型類型替換成原始類型以保證向后兼容性 ( 兼容不支持泛型的舊版本 Java ) , 向類 , 接口或方法傳遞的泛型類型參數 類名<類型> 只在編譯期存在 , 編譯后泛型信息會被擦除 , 生成的字節碼文件不包含具體的泛型類型 .

類型參數被擦除為它的第一個邊界類型 : 如果是 T , 則擦除為祖宗類 Object , 如果是 T extends 父類 , 則擦除為父類 . 集合中 List<T> 擦除為 List .

List<String> list = new ArrayList<>();
List.add("Hello");
String s = List.get(0);👇
(在字節碼中類似于)
List list = new ArrayList();
list.add("Hello");
String s = (String)list.get(0);

instanceof 關鍵字用于判斷對象是否是某個類或其子類的實例 , a instanceof b 作為語句返回布氏值 .

Tips : 基本數據類型不具備繼承體系 , 也不是對象 , 不能被泛型的擦除機制處理 , 所以泛型必須使用基本數據類型的包裝類 .

類型擦除會導致

  1. 運行時不知道泛型類型 .

    List<String> a = new ArrayList<>();
    List<Integer> b = new ArrayList<>();
    a.equals(b); // true
    a.getClass() == b.getClass() // true
    
  2. 泛型不能用于靜態字段 . 因為不同泛型實例在運行時本質上是同一個類 , 它們會共享同一個靜態字段 , 如果這個靜態字段是泛型參數 T 的 , 那么就會出現實例類型沖突 ( 靜態字段只有一份 , 不同實例期望的類型卻不同 ) .

  3. 不能用 instanceof 關鍵字判別泛型類 . 因為不同的泛型類在運行時被擦除為同一個類 , 此時再使用 instanceof 關鍵字沒有任何意義 .

編譯期類型檢查

仍然以集合為例 , 編譯期完成的任務有 :

  1. 檢測傳入泛型集合的字段類型是否正確 .

    List<String> list = new ArrayList<>();
    list.add("Hello");
    list.add(123); // 編譯錯誤, int 不是 String
    
  2. 取出泛型集合對象時是否能正確映射 .

    int get = list.get(0); // 編譯錯誤, 不能把 String 當作 int
    

類型檢查本質是繼承鏈的轉換關系 , 前面提到的向上轉型機制在通配符 , 類型擦除和類型檢查等特性上得到充分實現 .

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/83999.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/83999.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/83999.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

linux如何查找軟連接的實際地址

在Linux系統中&#xff0c;查找軟連接&#xff08;符號鏈接&#xff0c;即symbolic link&#xff09;的實際地址可以通過多種方法實現。軟連接是一個特殊的文件類型&#xff0c;它包含了一個指向另一個文件或目錄的引用。要找到軟連接所指向的實際文件或目錄&#xff0c;可以使…

Token類型與用途詳解:數字身份的安全載體圖譜

在現代數字身份體系中&#xff0c;Token如同"數字DNA"&#xff0c;以不同形態流轉于各類應用場景。根據Okta的最新研究報告&#xff0c;平均每個企業應用使用2.7種不同類型的Token實現身份驗證和授權。本文將系統梳理主流Token類型及其應用場景&#xff0c;通過行業典…

火山 RTC 引擎9 ----集成 appkey

一、集成 appkey 1、網易RTC 初始化過程 1&#xff09;、添加頭文件 實現互動直播 - 互動直播 2.0網易云信互動直播產品的基本功能包括音視頻通話和連麥直播&#xff0c;當您成功初始化 SDK 之后&#xff0c;您可以簡單體驗本產品的基本業務流程&#xff0c;例如主播加入房間…

詳細介紹Qwen3技術報告中提到的模型架構技術

詳細介紹Qwen3技術報告中提到的一些主流模型架構技術&#xff0c;并為核心流程配上相關的LaTeX公式。 這些技術都是當前大型語言模型&#xff08;LLM&#xff09;領域為了提升模型性能、訓練效率、推理速度或穩定性而采用的關鍵組件。 1. Grouped Query Attention (GQA) - 分組…

光電效應理論與實驗 | 從愛因斯坦光量子假說到普朗克常量測定

注&#xff1a;本文為“光電效應”相關文章合輯。 英文引文&#xff0c;機翻未校。 中文引文&#xff0c;略作重排&#xff0c;未整理去重。 圖片清晰度受引文原圖所限。 如有內容異常&#xff0c;請看原文。 Photoelectric Effect 光電效應 Discussion dilemma Under the…

Visual Studio 2019/2022:當前不會命中斷點,還沒有為該文檔加載任何符號。

1、打開調試的模塊窗口&#xff0c;該窗口一定要在調試狀態下才會顯示。 vs2019打開調試的模塊窗口 2、Visual Studio 2019提示未使用調試信息生成二進制文件 未使用調試信息生成二進制文件 3、然后到debug目錄下看下確實未生成CoreCms.Net.Web.WebApi.pdb文件。 那下面的…

打破性能瓶頸:用DBB重參數化模塊優化YOLOv8檢測頭

文章目錄 引言DBB 重參數化模塊簡介DBB 的優勢 YOLOv8 檢測頭的結構分析使用 DBB 模塊魔改檢測頭替換策略代碼實現改進后的效果預期 實驗與驗證總結與展望 引言 在目標檢測領域&#xff0c;YOLO 系列算法一直以其高效的檢測速度和不錯的檢測精度受到廣泛關注。隨著版本的不斷更…

如何成為更好的自己?

成為更好的自己是一個持續成長的過程&#xff0c;需要結合自我認知、目標規劃和行動力。以下是一些具體建議&#xff0c;幫助你逐步提升&#xff1a; 1. 自我覺察&#xff1a;認識自己 反思與復盤&#xff1a;每天花10分鐘記錄當天的決策、情緒和行為&#xff0c;分析哪些做得…

免費使用GPU的探索筆記

多種有免費時長的平臺 https://www.cnblogs.com/java-note/p/18760386 Kaggle免費使用GPU的探索 https://www.kaggle.com/ 注冊Kaggle賬號 訪問Kaggle官網&#xff0c;使用郵箱注冊賬號。 發現gpu都是灰色的 返回home&#xff0c;右上角的頭像點開 驗證手機號 再次code-you…

CSS- 4.2 相對定位(position: relative)

本系列可作為前端學習系列的筆記&#xff0c;代碼的運行環境是在HBuilder中&#xff0c;小編會將代碼復制下來&#xff0c;大家復制下來就可以練習了&#xff0c;方便大家學習。 HTML系列文章 已經收錄在前端專欄&#xff0c;有需要的寶寶們可以點擊前端專欄查看&#xff01; 點…

如何使用Antv X6使用拖拽布局?

拖拽效果圖 拖拽后 布局預覽 官方&#xff1a; X6 圖編輯引擎 | AntV 安裝依賴 # npm npm install antv/x6 --save npm install antv/x6-plugin-dnd --save npm install antv/x6-plugin-export --save需要引入的代碼 import { Graph, Shape } from antv/x6; import { Dnd } …

數據庫健康監測器(BHM)實戰:如何通過 HTML 報告識別潛在問題

在數據庫運維中,健康監測是保障系統穩定性與性能的關鍵環節。通過 HTML 報告,開發者可以直觀查看數據庫的運行狀態、資源使用情況與潛在風險。 本文將圍繞 數據庫健康監測器(Database Health Monitor, BHM) 的核心功能展開分析,結合 Prometheus + Grafana + MySQL Export…

PCB設計實踐(二十四)PCB設計時如何避免EMI

PCB設計中避免電磁干擾&#xff08;EMI&#xff09;是一項涉及電路架構、布局布線、材料選擇及制造工藝的系統工程。本文從設計原理到工程實踐&#xff0c;系統闡述EMI產生機制及綜合抑制策略&#xff0c;覆蓋高頻信號控制、接地優化、屏蔽技術等核心維度&#xff0c;為高密度、…

嵌入式硬件篇---陀螺儀|PID

文章目錄 前言1. 硬件準備主控芯片陀螺儀模塊電機驅動電源其他2. 硬件連接3. 軟件實現步驟(1) MPU6050初始化與數據讀取(2) 姿態解算(互補濾波或DMP)(3) PID控制器設計(4) 麥克納姆輪協同控制4. 主程序邏輯5. 關鍵優化與調試技巧(1) 傳感器校準(2) PID參數整定先調P再調D最后…

【Linux基礎I/O】文件調用接口、文件描述符、重定向和緩沖區

【Linux基礎I/O一】文件描述符和重定向 1.C語言的文件調用接口2.操作系統的文件調用接口2.1open接口2.2close接口2.3write接口2.4read接口 3.文件描述符fd的本質4.標準輸入、輸出、錯誤5.重定向5.1什么是重定向5.2輸入重定向和輸出重定向5.3系統調用的重定向dup2 6.緩沖區 1.C語…

鴻蒙HarmonyOS 【ArkTS組件】通用屬性-背景設置

&#x1f4d1;往期推文全新看點&#xff08;附帶最新鴻蒙全棧學習筆記&#xff09; 嵌入式開發適不適合做鴻蒙南向開發&#xff1f;看完這篇你就了解了~ 鴻蒙崗位需求突增&#xff01;移動端、PC端、IoT到底該怎么選&#xff1f; 分享一場鴻蒙開發面試經驗記錄&#xff08;三面…

【76. 最小覆蓋子串】

Leetcode算法練習 筆記記錄 76. 最小覆蓋子串 76. 最小覆蓋子串 滑動窗口的hard題目&#xff0c;思路先找到第一個覆蓋的窗口&#xff0c;不斷縮小左邊界&#xff0c;找到更小的窗口并記錄。 思路很簡單&#xff0c;寫起來就不是一會事了&#xff0c;看題解看了幾個h&#xff0…

Spring事務簡單操作

什么是事務&#xff1f; 事務是一組操作的集合&#xff0c;是一個不可分割的操作 事務會把所有的操作作為?個整體, ?起向數據庫提交或者是撤銷操作請求. 所以這組操作要么同時 成功, 要么同時失敗. 事務的操作 分為三步&#xff1a; 1. 開啟事start transaction/ begin …

Rust 學習筆記:關于錯誤處理的練習題

Rust 學習筆記&#xff1a;關于錯誤處理的練習題 Rust 學習筆記&#xff1a;關于錯誤處理的練習題想看到回溯&#xff0c;需要把哪個環境變量設置為 1&#xff1f;以下哪一項不是使用 panic 的好理由&#xff1f;以下哪一項最能描述為什么 File::open 返回的是 Result 而不是 O…

MCP 協議傳輸機制大變身:拋棄 SSE,投入 Streamable HTTP 的懷抱

在技術的江湖里&#xff0c;變革的浪潮總是一波接著一波。最近&#xff0c;模型上下文協議&#xff08;MCP&#xff09;的傳輸機制就搞出了大動靜&#xff0c;決定和傳統的服務器發送事件&#xff08;SSE&#xff09;說拜拜&#xff0c;轉身擁抱 Streamable HTTP&#xff0c;這…