Java 泛型與類型擦除:為什么解析對象時能保留泛型信息?

引言:泛型的“魔術”與類型擦除的困境

在 Java 中,泛型為開發者提供了類型安全的集合操作,但其背后的**類型擦除(Type Erasure)**機制卻常常讓人困惑。你是否遇到過這樣的場景?

List<String> list = new ArrayList<>();
list.add("Hello");
// 運行時無法通過 list.getClass() 獲取泛型類型 String

這種運行時泛型信息的丟失,可能導致 JSON 反序列化失敗或類型轉換錯誤。但有趣的是,當我們反序列化一個完整的對象時,泛型卻能奇跡般地被正確識別。本文將揭開這一現象的底層原理,并通過實際代碼示例為你解惑。


一、類型擦除的本質與影響

1.1 什么是類型擦除?

Java 泛型是編譯時特性。為了兼容舊版本 JVM,編譯器會移除所有泛型信息:

  • List<String> 在編譯后會變為原始類型 List
  • 泛型類型參數(如 String)僅在編譯階段進行類型檢查。

1.2 運行時為何無法直接獲取泛型?

public static void main(String[] args) {List<String> stringList = new ArrayList<>();System.out.println(stringList.getClass()); // 輸出:class java.util.ArrayList(無法看到 String 類型)
}

根本原因:泛型信息未被寫入字節碼,運行時 JVM 只能看到原始類型。


二、解析整個對象時的“魔法”:為什么泛型能保留?

2.1 實際場景分析

假設有以下類定義(來自用戶提供的代碼):

public class Event {// 關鍵字段:泛型集合private List<String> questions;
}

當使用 JSON 框架反序列化時:

Event  event = JsonUtil.parseObject(jsonStr, Event .class);

問題:為何 questions字段的泛型類型 String能被正確識別?

2.2 核心原理揭秘

原理 ①:類結構保留了泛型元數據
  • 編譯時記錄:雖然運行時類型擦除了泛型,但類的字段聲明(如 private List<String> questions;)的泛型信息會被記錄在 .class 文件的元數據中。
  • 反射可讀取:通過 Java 反射 API 的 Field.getGenericType() 方法,可以獲取字段的完整泛型類型。
原理 ②:JSON 框架的智能處理
  • 步驟拆解
    1. 解析目標類 Event.class
    2. 掃描字段questions,發現其類型為 List<String>
    3. 通過反射獲取泛型參數String的類型信息。
    4. 根據類型信息反序列化 JSON 數組中的每個元素。
關鍵代碼驗證
Field field = Event.class.getDeclaredField("questions");
Type genericType = field.getGenericType();// 輸出:java.util.List<java.lang.String>
System.out.println(genericType); 

三、單獨解析集合的困境與解決方案

3.1 問題場景

如果直接解析一個純集合 JSON:

[{"content": "題目1"},{"content": "題目2"}
]

嘗試反序列化:

List<AbstractTopicDto> list = JsonUtil.parseObject(jsonStr, List.class); // ? 失敗!

此時,由于類型擦除,List.class 無法提供泛型信息,框架無法知道元素的具體類型。

3.2 解決方案:TypeReference 的妙用

通過匿名內部類保留泛型信息:

List<String> list = JsonUtil.parseObject(jsonStr, new TypeReference<List<String>>() {} // ? 匿名類攜帶泛型信息
);
原理解釋
  • 匿名類繼承TypeReference<List<String>> 的子類在編譯時會保留泛型參數。
  • 框架讀取方式:通過 getGenericSuperclass() 方法獲取父類的泛型類型。

四、對比總結:何時泛型信息可用?

場景是否保留泛型原因
直接訪問 List 變量的泛型? 否類型擦除后運行時無信息
解析完整對象(如Event? 是類字段的泛型信息保存在元數據中,可通過反射獲取
使用 TypeReference? 是匿名內部類的泛型參數通過父類類型保留

五、最佳實踐與避坑指南

  1. 優先傳遞完整對象類型
    在反序列化時,盡量傳遞包含泛型字段的類(如 Event.class),而非直接操作集合。

  2. 避免裸類型(Raw Type)
    不要使用 List.classMap.class,而應通過 TypeReference 指定泛型。

  3. 謹慎使用反射獲取泛型
    若需手動處理泛型,確保理解 ParameterizedTypeTypeVariable 的區別。

  4. 單元測試驗證泛型行為
    針對泛型字段編寫測試,確保序列化/反序列化邏輯正確。


結語:泛型的“可見性”取決于上下文

Java 的類型擦除機制雖然帶來了限制,但通過類結構的元數據和框架的智能處理,我們仍然能在關鍵場景下“找回”泛型信息。理解這一機制,能夠幫助開發者更高效地處理 JSON 序列化、反射操作等復雜場景。正如代碼中的Event所示,合理設計對象結構,可以讓泛型在運行時“隱而不失”,繼續發揮其類型安全的威力。

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

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

相關文章

【gRPC】HTTP/2協議,HTTP/1.x中線頭阻塞問題由來,及HTTP/2中的解決方案,RPC、Protobuf、HTTP/2 的關系及核心知識點匯總

HTTP/2協議特點 gRPC基于HTTP/2協議&#xff0c;原因&#xff1a; 多路復用&#xff1a;允許在同一個TCP連接上并行傳輸多個請求和響應&#xff0c;即多個gRPC調用可以通過同一個連接同時進行&#xff0c;避免了HTTP/1.x中常見的線頭阻塞問題&#xff0c;減少了連接建立和關閉…

PCIe Switch 問題點

系列文章目錄 文章目錄 系列文章目錄完善PCIe Retimer Overview Document OutlineSwitch 維度BroadComMicroChipAsmedia 祥碩Cyan其他 完善 Functional block diagram&#xff0c;功能框圖Key Features and Benefits&#xff0c;主要功能和優點Fabric 鏈路Multi-root PCIe Re…

vue復雜數據類型多層嵌套的監聽

vue復雜數據類型多層嵌套的監聽 本來看前輩的做法是watch的嵌套&#xff0c;遇到這種復雜的數據結構還是不多&#xff0c;分享一下前輩的做法 let stopChildWatchList [] // 用于存放每個子監聽器watch(() > data,(val) > {// 清除舊監聽stopChildWatchList.forEach(…

來一個復古的技術FTP

背景 10年前的老代碼&#xff0c;需要升級springboot框架&#xff0c;在升級過程中&#xff0c;測試業務流程里&#xff0c;有FTP的下載業務&#xff0c;不管測試環境如何測試&#xff0c;都沒有成功&#xff0c;最后只能自己搭建一個FTP服務器&#xff0c;寫一個ftp-demo來測試…

MyBatis-Flex配置Druid(德魯伊數據庫連接池):Spring Boot 3 集成 MyBatis-Flex 配置 Druid 連接池指南

Spring Boot 3 集成 MyBatis-Flex 配置 Druid 連接池指南 前言 本文詳細講解在 Spring Boot 3 項目中集成 MyBatis-Flex 框架后&#xff0c;如何正確配置 Druid 數據庫連接池。針對開發者常見的配置缺失導致啟動失敗的場景&#xff0c;提供完整的解決方案和原理分析。 前置知識…

安全生產調度管理系統的核心功能模塊

安全生產調度管理系統是運用現代信息技術構建的智能化管理平臺&#xff0c;旨在實現生產安全風險的全面管控和應急資源的優化調度。該系統通過整合物聯網、大數據、人工智能等前沿技術&#xff0c;建立起覆蓋風險監測、預警預測、指揮調度、決策支持的全鏈條安全管理體系。 一…

桃芯ingchips——windows HID鍵盤例程無法同時連接兩個,但是安卓手機可以的問題

目錄 環境 現象 原理及解決辦法 環境 PC&#xff1a;windows11 安卓&#xff1a;Android14 例程使用的是HID Keyboard&#xff0c;板子使用的是91870CQ的開發板&#xff0c;DB870CC1A 現象 連接安卓手機時并不會出現該現象&#xff0c;兩個開發板都可以當做鍵盤給手機發按…

JavaScript - JavaScript 運算符之圓括號運算符與方括號運算符(圓括號運算符概述、圓括號運算符用法、方括號運算符概述、方括號運算符用法)

一、圓括號運算符概述 圓括號運算符&#xff08;()&#xff09;主要用于函數調用、表達式分組、多種語法結構登 二、圓括號運算符用法 調用函數 function greet() {console.log("Hello!"); }greet();# 輸出結果Hello!當箭頭函數有多個參數或零個參數時需要括號 c…

AG-UI 協議:重構多模態交互,開啟智能應用新紀元

一、協議誕生的時代背景&#xff1a;填補 AI 生態最后一塊拼圖 在人工智能技術飛速發展的今天&#xff0c;AI 代理&#xff08;Agent&#xff09;作為能夠主動執行復雜任務的智能實體&#xff0c;正從實驗室走向生產環境&#xff0c;重塑各個行業的工作流程。然而&#xff0c;…

嵌入式學習的第二十天-數據結構-調試+鏈表的一般操作

一、調試 1.一般調試 2.找段錯誤 二、鏈表的一般操作 1.單鏈表的修改 int ModifyLinkList(LinkList*ll,char*name,DATATYPE*data) {DATATYPE * tmp FindLinkList(ll, name);if(NULL tmp){return 1;}memcpy(tmp,data,sizeof(DATATYPE));return 0; } 2.單鏈表的銷毀 int D…

如何同時管理不同平臺的多個賬號?

在當今數字營銷、電商運營、跨境貿易盛行的時代&#xff0c;同時管理多個平臺的賬號幾乎成了從業者的標配。無論是做社媒營銷的廣告主&#xff0c;還是操作亞馬遜、eBay、Shopee 等平臺的跨境賣家&#xff0c;多賬號運營都是提升曝光、分散風險、擴大收益的重要方式。 然而&am…

STM32外設AD/DA-基礎及CubeMX配置

STM32外設AD/DA-基礎及CubeMX配置 一&#xff0c;什么是AD/DA二&#xff0c;基礎概念1&#xff0c;模擬 vs 數字2&#xff0c;AD轉換1&#xff0c;分辨率 (Resolution)2&#xff0c;參考電壓 (Reference Voltage, Vref)3&#xff0c;采樣率 (Sampling Rate) 3&#xff0c;DA轉換…

【軟考 霍夫曼編碼的文檔壓縮比】

霍夫曼編碼的文檔壓縮比計算基于字符頻率的最優編碼分配&#xff0c;以下是詳細步驟及相關案例&#xff1a; 一、壓縮比計算公式 [ \text{壓縮比} \frac{\text{壓縮前總比特數}}{\text{壓縮后總比特數 編碼表存儲開銷}} ] 通常以 比率&#xff08;如 3:1&#xff09; 或 百分…

關閉VSCode 自動更新

參考&#xff1a;關閉VSCode 自動更新_vscode關閉自動更新-CSDN博客 vscode的設置 Update: Mode Update: Enable Windows Background Updates Extensions: Auto Check Updates Extensions: Auto Update

Flask框架搭建

1、安裝Flask 打開終端運行以下命令&#xff1a; pip install Flask 2、創建項目目錄 在Windows上&#xff1a; venv\Scripts\activate 執行 3、創建 app.py 文件 可以在windows終端上創建app.py文件 &#xff08;1&#xff09;終端中創建 使用echo命令 echo "fr…

5G-A和未來6G技術下的操作系統與移動設備變革:云端化與輕量化的發展趨勢

目錄 5G技術帶來的革命性變革 云端化操作系統的實現路徑 完全云端化模式 過渡性解決方案 未來操作系統的發展方向 功能架構演進 安全機制強化 移動設備的形態變革 終端設備輕量化 物聯網設備簡化 實施挑戰與應對策略 技術挑戰 商業模式創新 總結與展望 5G技術作為…

【漫話機器學習系列】261.工具變量(Instrumental Variables)

工具變量&#xff08;Instrumental Variables&#xff09;通俗圖解&#xff1a;破解內生性困境的利器 在數據建模與因果推斷過程中&#xff0c;我們經常遇到一個棘手問題&#xff1a;內生性&#xff08;Endogeneity&#xff09;。它會導致模型估計產生偏差&#xff0c;進而誤導…

CSS:顏色的三種表示方式

文章目錄 一、rgb和rgba方式二、HEX和HEXA方式&#xff08;推薦&#xff09;三、hsl和hsla方式四、顏色名方式 一、rgb和rgba方式 10進制表示方法 二、HEX和HEXA方式&#xff08;推薦&#xff09; 就是16進制表示法 三、hsl和hsla方式 語法&#xff1a;hsl(hue, satura…

支付寶授權登錄

支付寶授權登錄 一、場景 支付寶小程序登錄&#xff0c;獲取用戶userId 二、注冊支付寶開發者賬號 1、支付寶開放平臺 2、點擊右上角–控制臺&#xff0c;創建小程序 3、按照步驟完善信息&#xff0c;生成密鑰時會用到的工具 4、生成的密鑰&#xff0c;要保管好&#xff…

涂色不踩雷:如何優雅解決 LeetCode 柵欄涂色問題

文章目錄 摘要描述例子&#xff1a; 題解答案&#xff08;Swift&#xff09;題解代碼分析動態規劃核心思路初始條件 示例測試及結果示例 1&#xff1a;示例 2&#xff1a;示例 3&#xff1a; 時間復雜度空間復雜度總結實際場景聯系 摘要 在用戶體驗和界面設計中&#xff0c;顏…