先看如下一個DEMO示例代碼:(其中doBatchGet被子類重寫了1次) public abstract class BaseDemoService<T> { public String batchGet(T... ints) { T one=ints[0]; System.out.println ...
先看如下一個DEMO示例代碼:(其中doBatchGet被子類重寫了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();
}
}
@Service
public class Demo1Service extends BaseDemoService<Integer> {
@Override
public String doBatchGet(Integer... ints) {
System.out.println("com.example.springwebapp.service.Demo1Service.doBatchGet");
return super.doBatchGet(ints);
}
@Override
public String doGet(Integer one) {
return super.doGet(one);
}
}
執行單元測試,示例代碼如下:
@Resource
private BaseDemoService baseDemoService;
@Test
public void testOverride(){
Integer[] ints={1,2,3,4,5,6};
System.out.println("batchGet result:" + baseDemoService.batchGet(ints));
}
大家認為最後batchGet result輸出的結果如何?有人可能會認為這太簡單了,就是1,但實際上的結果可能會讓你打臉,居然直接報錯,如下所示:
one class:java.lang.Integer
java.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)
... ...
報錯的意思是類型轉換錯誤,object數組類型不能轉換為integer數組類型,但我上面一行明明輸出的結果就是one class:java.lang.Integer,為何傳給doBatchGet就變成了object類型呢?是不是有點看不懂了,編譯也是正常的,但運行就是報錯,如果把入參的ints直接傳到doBatchGet方法入參中也是OK的,或者內部將doBatchGet改為doGet,即使子類重寫doGet一樣可以正確獲取結果 又或者doBatchGet沒有被子類重寫也可以正確獲得結果,但如果單獨從ints中取一個成員然後再調doBatchGet方法就會報錯,大家知道為啥嗎?
我這裡就不賣關子了,其實就是泛型參數類型擦除“惹的禍”,因為別看我們是BaseDemoService
當我們知道了問題原因後,那麼就可以對症下藥了.
解法一(關鍵點:通過反射創建一個入參真實類型的數組,這個數組與doBatchGet入參類型一致):
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);
}
解法二(關鍵點:將doBatchGet由原來的可變參數直接改為List,這樣即使子類重寫,因為List本身就是泛型,所以擦除了就都是一樣的):
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();
}
以上就是實際項目中碰到的問題及解法,希望對大家也有幫助。