关于JAVA泛型数组类型擦除引发的问题及解决方案
先看如下一个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,其实这个T在编译后就是一个Object,在从ints取出一个成员值one后,虽然指明是T,但实际就是Object,最后在调doBatchGet的时候,JVM会将one这个变量隐式转换为one的Object数组,然后调doBatchGet,由于doBatchGet方法被子类重写,而重写后入参是具体的类型(Integer数组),这样就导致了上面的object数组类型不能转换为integer数组类型的错误。
当我们知道了问题原因后,那么就可以对症下药了.
解法一(关键点:通过反射创建一个入参真实类型的数组,这个数组与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();
}
以上就是实际项目中碰到的问题及解法,希望对大家也有帮助。
关于JAVA泛型数组类型擦除引发的问题及解决方案的更多相关文章
- Java泛型:类型擦除
类型擦除 代码片段一 Class c1 = new ArrayList<Integer>().getClass(); Class c2 = new ArrayList<String& ...
- Java泛型之类型擦除
类型擦除 学过C++模板的,在使用Java泛型的时候,会感觉到有点不疑问,例如:(1)无法定义一个泛型数组.无法调用泛型参数对象中对应的方法(当然,通过extends关键字是可以做到,只是比较麻烦): ...
- java 泛型的类型擦除和桥方法
oracle原文地址:https://docs.oracle.com/javase/tutorial/java/generics/erasure.html 在Java中,泛型的引入是为了在编译时提供强 ...
- Java泛型-类型擦除
一.概述 Java泛型在使用过程有诸多的问题,如不存在List<String>.class, List<Integer>不能赋值给List<Number>(不可协变 ...
- 转:有关Java泛型的类型擦除(type erasing)
转载自:拈花微笑 自从Java 5引入泛型之后,Java与C++对于泛型不同的实现的优劣便一直是饭后的谈资.在我之前的很多training中,当讲到Java泛型时总是会和C++的实现比较,一般得出的结 ...
- java 泛型的类型擦除与桥方法
泛型类 --代码参考:java核心技术 卷1 第十版 public class Pair<T> { private T first; private T second; //构造器 pub ...
- JAVA 泛型之类型擦除
★ 泛型是 JDK 1.5 版本引进的概念,之前是没有泛型的概念的,但泛型代码能够很好地和之前版本的代码很好地兼容. CollectionTest.java ---编译成CollectionTest. ...
- Java泛型的类型擦除
package com.srie.testjava; import java.util.ArrayList; import java.util.List; public class TestGener ...
- Java泛型类与类型擦除
转载自:http://blog.csdn.net/lonelyroamer/article/details/7868820 一.Java泛型的实现方法:类型擦除 前面已经说了,Java的泛型是伪泛型. ...
- java之集合类框架的简要知识点:泛型的类型擦除
这里想说一下在集合框架前需要理解的小知识点,也是个人的肤浅理解,不知道理解的正不正确,请大家多多指教.这里必须谈一下java的泛型,因为它们联系紧密,我们先看一下这几行代码: Class c1 = n ...
随机推荐
- 2021年vivo互联网技术最受欢迎文章TOP25
岁月流转,时光飞逝,转眼2021年已经画上句号.过去一年,vivo 互联网技术共推送了107篇文章,涉及服务器.前端.数据库等技术. 今天小编就带大家回顾一下2021年我们最受欢迎的25篇文章(根据阅 ...
- vue判断用户在页面停留时间是否超时
需求 当用户停留超过15分钟后,用户提交订单,提示用户超时并重新加载页面 代码 data () { return { // 超时定时器 overTimer: null, // 是否超时 isOvert ...
- 俩小伙一晚上写了个 AI 应用,月入两万??(文末附开发教程)
开发出一款能够与 AI 对话生成和编辑思维导图的工具,听起来似乎只能是一群专业的 AI 背景团队花费大量的时间和精力训练模型,打磨应用才能完成的事情. 但是,两名大学生却在一夜之间完成了,就像炼金术士 ...
- C#使用正则表达式检查字符串中重复出现的词
private void button1_Click(object sender, EventArgs e) { MatchCollection matches =//使用正则表达式查找重复出现单词的 ...
- centos7使用nginx+uwsgi部署python django项目
在django框架中,我们一般直接通过python manage.py runserver来启动提供服务,但是如果生产环境此方法不可行,而且容易导致异常退出,于是需要借助uwsgi来作为守护进程. 操 ...
- LLM面面观之Prefix LM vs Causal LM
1. 背景 关于Prefix LM和Causal LM的区别,本qiang在网上逛了一翻,发现多数客官只给出了结论,但对于懵懵的本qiang,结果仍是懵懵... 因此,消遣了多半天,从原理及出处,交出 ...
- 2023 SHCTF-校外赛道 MISC WP
WEEK1 请对我使用社工吧 提示:k1sme4的朋友考到了一所在k1sme4家附近的大学,一天,k1sme4的朋友去了学校对面的商场玩,并给k1sme4拍了一张照片,你能找到他的学校吗? flag格 ...
- 【Tomcat 组成与工作原理】
Tomcat组成与工作原理 Tomcat 是什么 开源的 Java Web 应用服务器,实现了 Java EE(Java Platform Enterprise Edition)的部 分技术规范,比如 ...
- [转帖]【split】Linux上用 split实现大文件的拆分和合并
https://www.jianshu.com/p/87748b8563a9 有没有遇到某些网站上传复件时,单个文件有大小限制,导致上传失败呢?当然你可以采用更高的压缩率重新生成压缩包来解决,但如果还 ...
- 极简版 haproxy的搭建步骤
背景 发现四层nginx的代理报错. 然后想着换用一下haproxy的配置. 早些时候 看过tidb的一些最佳时间, 这里简单整理一下. 下载 https://src.fedoraproject.or ...