關(guān)于JAVA泛型數(shù)組類型擦除引發(fā)的問(wèn)題及解決方案
先看如下一個(gè)DEMO示例代碼:(其中doBatchGet被子類重寫(xiě)了1次)
public abstract class BaseDemoService<T> { ? ?public String batchGet(T... ints) {
? ? ? ?T one=ints[0];
? ? ? ?System.out.println("one class:" + one.getClass().getCanonicalName()); ? ? ? ?return doBatchGet(one);
? ?} ? ?public String doBatchGet(T... ints){
? ? ? ?System.out.println("com.example.springwebapp.service.Demo1Service.doBatchGet"); ? ? ? ?return String.join(",", Arrays.toString(ints));
? ?} ? ?
? ?public String doGet(T one){ ? ? ? ?return one.toString();
? ?}
} ? ?public class Demo1Service extends BaseDemoService<Integer> { ? ?
? ?public String doBatchGet(Integer... ints) {
? ? ? ?System.out.println("com.example.springwebapp.service.Demo1Service.doBatchGet"); ? ? ? ?return super.doBatchGet(ints);
? ?} ? ?
? ?public String doGet(Integer one) { ? ? ? ?return super.doGet(one);
? ?}
} ? ?
執(zhí)行單元測(cè)試,示例代碼如下:
? ?private BaseDemoService baseDemoService; ? ?
? ?public void testOverride(){
? ? ? ?Integer[] ints={1,2,3,4,5,6};
? ? ? ?System.out.println("batchGet result:" + baseDemoService.batchGet(ints));
? ?}
? ?
大家認(rèn)為最后batchGet result輸出的結(jié)果如何?有人可能會(huì)認(rèn)為這太簡(jiǎn)單了,就是1,但實(shí)際上的結(jié)果可能會(huì)讓你打臉,居然直接報(bào)錯(cuò),如下所示:
one class:java.lang.Integerjava.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [Ljava.lang.Integer;
at com.example.springwebapp.service.Demo1Service.doBatchGet(Demo1Service.java:5) at com.example.springwebapp.service.BaseDemoService.batchGet(BaseDemoService.java:11) at com.example.springwebapp.Springwebapp1ApplicationTests.testOverride(Springwebapp1ApplicationTests.java:38)... ...
報(bào)錯(cuò)的意思是類型轉(zhuǎn)換錯(cuò)誤,object數(shù)組類型不能轉(zhuǎn)換為integer數(shù)組類型,但我上面一行明明輸出的結(jié)果就是one class:java.lang.Integer,為何傳給doBatchGet就變成了object類型呢?是不是有點(diǎn)看不懂了,編譯也是正常的,但運(yùn)行就是報(bào)錯(cuò),如果把入?yún)⒌膇nts直接傳到doBatchGet方法入?yún)⒅幸彩荗K的,或者內(nèi)部將doBatchGet改為doGet,即使子類重寫(xiě)doGet一樣可以正確獲取結(jié)果 又或者doBatchGet沒(méi)有被子類重寫(xiě)也可以正確獲得結(jié)果,但如果單獨(dú)從ints中取一個(gè)成員然后再調(diào)doBatchGet方法就會(huì)報(bào)錯(cuò),大家知道為啥嗎?
我這里就不賣關(guān)子了,其實(shí)就是泛型參數(shù)類型擦除“惹的禍”,因?yàn)閯e看我們是BaseDemoService,其實(shí)這個(gè)T在編譯后就是一個(gè)Object,在從ints取出一個(gè)成員值one后,雖然指明是T,但實(shí)際就是Object,最后在調(diào)doBatchGet的時(shí)候,JVM會(huì)將one這個(gè)變量隱式轉(zhuǎn)換為one的Object數(shù)組,然后調(diào)doBatchGet,由于doBatchGet方法被子類重寫(xiě),而重寫(xiě)后入?yún)⑹蔷唧w的類型(Integer數(shù)組),這樣就導(dǎo)致了上面的object數(shù)組類型不能轉(zhuǎn)換為integer數(shù)組類型的錯(cuò)誤。
當(dāng)我們知道了問(wèn)題原因后,那么就可以對(duì)癥下藥了.
解法一(關(guān)鍵點(diǎn):通過(guò)反射創(chuàng)建一個(gè)入?yún)⒄鎸?shí)類型的數(shù)組,這個(gè)數(shù)組與doBatchGet入?yún)㈩愋鸵恢?:
? ?public String batchGet(T... ints) {
? ? ? ?T[] arr = (T[]) Array.newInstance(ints[0].getClass(), 1);
? ? ? ?arr[0]=ints[0];
? ? ? ?System.out.println("arr class:" + arr.getClass().getCanonicalName()); ? ? ? ?return doBatchGet(arr);
? ?}
解法二(關(guān)鍵點(diǎn):將doBatchGet由原來(lái)的可變參數(shù)直接改為L(zhǎng)ist,這樣即使子類重寫(xiě),因?yàn)長(zhǎng)ist本身就是泛型,所以擦除了就都是一樣的):
? ?public String batchGet(T... ints) { ? ? ? ?return doBatchGet(Arrays.asList(ints));
? ?}public String doBatchGet(List<T> ints){
? ? ? ?System.out.println("com.example.springwebapp.service.Demo1Service.doBatchGet"); ? ? ? ?return ints.toString();
? ?}
以上就是實(shí)際項(xiàng)目中碰到的問(wèn)題及解法,希望對(duì)大家也有幫助。