頭次寫博客,想說的東西不難,關(guān)于泛型的疑問,是前一陣在學習jackson中遇到的。
下面就把我所想到的、遇到的,分享出來。
泛型是JDK1.5后的一個特性,是一個參數(shù)類型的應用,可以將這個參數(shù)聲明在類、接口、方法中,就像我們方法中定義的局部變量一樣;在工作中,我們常在List,Map,Set等集合對象中使用,或者我們自己聲明的類中使用。
說到泛型,就不得說起“擦除”這個概念,相比于c#來說,java的泛型只存在于程序的源碼中,在編譯后的class文件中不存在,這個過程就是--泛型"擦除";所以,對于new ArrayList<String> 和 new ArrayList<Integer> 來說,兩個對象在編譯之后兩者是一樣的,通過反射均可以向集合中添加任意類型的對象;


可以看到,在編譯后的class文件中,ArrayList所聲明的泛型不存在了;由此可知,如果想在程序運行期間獲取泛型,看似是一件不可能完成的事情!
直到學習了jackson后,我發(fā)現(xiàn)java泛型的“擦除”并不能一概而論;至少通過TypeReference接口,是可以獲取到對象中的泛型;

一開始學習jackson,相關(guān)的api操作還不是很熟悉,json并沒有轉(zhuǎn)換成StudentEntity對象,而是變成了LinkedHashMap;研究后,發(fā)現(xiàn)可以使用TypeReference對象,來實現(xiàn)參數(shù)化類型的json轉(zhuǎn)換;

有些疑問?按照之前所說,由于泛型“擦除”的原因,泛型在編譯后的class文件中就不存在了,只會保留原始類型(Type中的概念),那么TypeReference又是如何實現(xiàn),獲取到了具體的泛型類型呢!
查看TypeReference的源碼,發(fā)現(xiàn)在其構(gòu)造方法中,主要使用到了getGenericSuperclass()和getActualTypeArguments
()兩個方法,getGenericSuperclass()返回的是此對象帶“泛型”的父類,而getActualTypeArguments()返回的是此父類中實際類型參數(shù)的Type 對象數(shù)組,說白了就是TypeReference<>中的泛型;

通過debug,發(fā)現(xiàn)確實獲取到了new TypeReference<Map<String,StudentEntity>>中的泛型,至此我決定自己寫個父類、子類,看看效果如何?

再次通過debug發(fā)現(xiàn),并沒有得到具體的泛型,而是獲取到了ParameterizedTypeImpl對象(Type中的概念);此時,對于泛型更加疑惑了,感覺心中有千萬只草泥馬在奔騰!
于是,又回過頭來看了下之前的代碼 new TypeReference<Map<String,StudentEntity>>(){},發(fā)現(xiàn)此段代碼其實是一個匿名的內(nèi)部類,而編譯器在編譯的時候,會將此匿名內(nèi)部類單獨生成一個class文件,命名規(guī)則如下:主類+$+(1,2,3....)

通過反編譯后,真相一目了然!

創(chuàng)建的匿名內(nèi)部類new TypeReference<Map<String,StudentEntity>>(){},在生成的的class文件中,編譯器默認為TypeReference中的泛型Map<String,StudentEntity>原始類型,并不會進行擦除!類似于 我們實際創(chuàng)建一個類 Class TypeReference<Map<String,StudentEntity>>{}?、 Class Test<T>{}一樣,在編譯后Map、T依舊會存在!
由此,對于java泛型的“擦除”并不能一概而論,在運行期間,如果方法中出現(xiàn)帶泛型的匿名內(nèi)部類,那么泛型依舊會被保留下來,我們可以通過對應的方法獲取到實際的泛型類型!
上文中,提到的Type、原始類型的概念,在下一篇博客中提及!