<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
Java語言的泛型採用的是擦除法實現的偽泛型,泛型資訊(型別變數、引數化型別)編譯之後通通被除掉了。使用擦除法的好處就是實現簡單、非常容易Backport,執行期也能夠節省一些型別所佔的記憶體空間。
而擦除法的壞處就是,通過這種機制實現的泛型遠不如真泛型靈活和強大。Java選取這種方法是一種折中,因為Java最開始的版本是不支援泛型的,為了相容以前的庫而不得不使用擦除法。
驗證擦除,我們編寫下面程式碼:
public class ErasedTypeEquivalence { public static void main(String[] args) { //例1 ArrayList<String> list1 = new ArrayList<String>(); list1.add("abc"); ArrayList<Integer> list2 = new ArrayList<Integer>(); list2.add(123); System.out.println(list1.getClass() == list2.getClass());//true //例2 ArrayList<Integer> list = new ArrayList<Integer>(); list.add(1); //這樣呼叫 add 方法只能儲存整形,因為泛型型別的範例為 Integer list.getClass().getMethod("add", Object.class).invoke(list, "asd"); for (int i = 0; i < list.size(); i++) { System.out.println(list.get(i));//會輸出1和asd } } }
在例1中,我們定義了兩個ArrayList陣列,不過一個是ArrayList<String>泛型型別的,只能儲存字串;一個是ArrayList<Integer>泛型型別的,只能儲存整數,最後,我們通過list1物件和list2物件的getClass()方法獲取他們的類的資訊,最後發現結果為true。說明泛型型別String和Integer都被擦除掉了,只剩下原始型別。
在例2中,定義了一個ArrayList泛型型別範例化為Integer物件,如果直接呼叫add()方法,那麼只能儲存整數資料,不過當我們利用反射呼叫add()方法的時候,卻可以儲存字串,這說明了Integer泛型範例在編譯之後被擦除掉了,只保留了原始型別。
上面兩次提到了原始型別,什麼是原始型別?原始型別 就是擦除去了泛型資訊,最後在位元組碼中的型別變數的真正型別,無論何時定義一個泛型,相應的原始型別都會被自動提供,型別變數擦除,並使用其限定型別(無限定的變數用Object)替換。
最近在搭系統基礎程式碼架構,其中就涉及到系統資料字典 功能,以前都是用varchar型別儲存字典內容,這次準備玩點新花樣,準備用上MySQL的JSON型別儲存字典表的內容欄位。>>文章傳送門<<
實際操作之後就遇到了泛型擦除問題,如下圖,我雖然對content欄位的List指定了泛型DictContent,但是在做型別轉換時,只能指定javaType=List,沒有也不能指定其泛型:
在沒有指定泛型的情況下,JacksonTypeHandler在做型別轉換後生成的集合的泛型就與預期的不一致:
原因很簡單,在resultMap中指定的JavaType是java.util.List,此處只能指定類型別,並不能指定泛型。而在對應的型別轉換類中也沒有指定其泛型,而List<DictContent>和List<Object>的類型別是一樣的,所以在給content欄位賦值時是不會報錯的。但是一旦你需要操作List的中的元素,在取出元素時,JVM就發現你要的型別是DictContent 而實際上是LinkedHashMap,就會丟擲型別轉換異常。
通俗的講就是你準備買華為手機(將JSON型別轉成List<DictContent>型別),但是買的時候沒有說要買什麼牌子的手機(在javaType中只指定了List型別,沒有也無法指定泛型),而店子裡有很多牌子的手機,所以店家就隨便給了你一款手機。。。
以下是Mybatis Plus中的部分原始碼,可以看到在沒有指定List的泛型的情況下,通過JacksonTypeHandler處理後的元素型別並不是我們預期的型別:
下圖我們可以看到JacksonTypeHandler是BaseTypeHandler的子類,而且指定了BaseTypeHandler中的泛型是Object型別,但是上圖中的泛型卻是LinkedHashMap。
至於為什麼是LinkedHashMap,我覺得是JVM指定的,如果哪位大佬比較清楚這塊的邏輯還請在評論中指點一下!
既然原因搞清楚了,解決方案就呼之欲出了,有兩種方案:
以上兩種方案都可以實現我們的需求。
從工作量上來說,自定義一個List<T>顯然更少,所以我選擇了第一種方案,如圖:
8.11新增:第二種解決方式:
替換後結果如下:
至此,泛型擦除問題解決。
不得不說,玩新花樣總是會遇到各種各樣的坑,但是程式設計之路,不就是不斷的踩坑,不斷的改BUG,積累經驗,打怪升級。如果不是因為最近玩了這個新花樣,可能我這輩子都不會遇到泛型擦除的問題!
以上為個人經驗,希望能給大家一個參考,也希望大家多多支援it145.com。
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45