中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Mybatis泛型擦除問題如何解決

發布時間:2022-08-25 15:49:45 來源:億速云 閱讀:228 作者:iii 欄目:開發技術

這篇“Mybatis泛型擦除問題如何解決”文章的知識點大部分人都不太理解,所以小編給大家總結了以下內容,內容詳細,步驟清晰,具有一定的借鑒價值,希望大家閱讀完這篇文章能有所收獲,下面我們一起來看看這篇“Mybatis泛型擦除問題如何解決”文章吧。

概念介紹

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,沒有也不能指定其泛型:

Mybatis泛型擦除問題如何解決

在沒有指定泛型的情況下,JacksonTypeHandler在做類型轉換后生成的集合的泛型就與預期的不一致:

Mybatis泛型擦除問題如何解決

Mybatis泛型擦除問題如何解決

原因分析

原因很簡單,在resultMap中指定的JavaType是java.util.List,此處只能指定類類型,并不能指定泛型。而在對應的類型轉換類中也沒有指定其泛型,而List<DictContent>和List<Object>的類類型是一樣的,所以在給content字段賦值時是不會報錯的。但是一旦你需要操作List的中的元素,在取出元素時,JVM就發現你要的類型是DictContent 而實際上是LinkedHashMap,就會拋出類型轉換異常。

通俗的講就是你準備買華為手機(將JSON類型轉成List<DictContent>類型),但是買的時候沒有說要買什么牌子的手機(在javaType中只指定了List類型,沒有也無法指定泛型),而店子里有很多牌子的手機,所以店家就隨便給了你一款手機。。。

以下是Mybatis Plus中的部分源碼,可以看到在沒有指定List的泛型的情況下,通過JacksonTypeHandler處理后的元素類型并不是我們預期的類型:

Mybatis泛型擦除問題如何解決

下圖我們可以看到JacksonTypeHandler是BaseTypeHandler的子類,而且指定了BaseTypeHandler中的泛型是Object類型,但是上圖中的泛型卻是LinkedHashMap。

至于為什么是LinkedHashMap,我覺得是JVM指定的,如果哪位大佬比較清楚這塊的邏輯還請在評論中指點一下!

Mybatis泛型擦除問題如何解決

Mybatis泛型擦除問題如何解決

解決方案

既然原因搞清楚了,解決方案就呼之欲出了,有兩種方案:

  • 自定義一個指定泛型的集合類替代List<T>

  • 引用上文中通俗的說法,這個方案就是在買手機的時候告訴賣家,我要買華為手機。

  • 自定義一個指定泛型的TypeHandler類替代JacksonTypeHandler類

  • 而這里的的通俗的說法就是讓店家只賣華為手機。

以上兩種方案都可以實現我們的需求。

從工作量上來說,自定義一個List<T>顯然更少,所以我選擇了第一種方案,如圖:

Mybatis泛型擦除問題如何解決

8.11新增:第二種解決方式:

Mybatis泛型擦除問題如何解決

替換后結果如下:

Mybatis泛型擦除問題如何解決

以上就是關于“Mybatis泛型擦除問題如何解決”這篇文章的內容,相信大家都有了一定的了解,希望小編分享的內容對大家有幫助,若想了解更多相關的知識內容,請關注億速云行業資訊頻道。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

晋中市| 牟定县| 渭南市| 唐河县| 民勤县| 凤山县| 长垣县| 常熟市| 永济市| 乌恰县| 益阳市| 安溪县| 罗城| 信宜市| 繁昌县| 皮山县| 宝兴县| 厦门市| 美姑县| 东丰县| 宁津县| 会理县| 思茅市| 孝义市| 云和县| 泰顺县| 英山县| 南岸区| 巢湖市| 开封市| 安徽省| 神池县| 武山县| 石泉县| 莱西市| 吴川市| 和顺县| 广汉市| 卢湾区| 忻州市| 海丰县|