千家信息网

Java泛型中类型擦除问题怎么解决

发表于:2025-11-06 作者:千家信息网编辑
千家信息网最后更新 2025年11月06日,这篇"Java泛型中类型擦除问题怎么解决"文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇
千家信息网最后更新 2025年11月06日Java泛型中类型擦除问题怎么解决

这篇"Java泛型中类型擦除问题怎么解决"文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇"Java泛型中类型擦除问题怎么解决"文章吧。

假设有两个bean类

/** Test. */@Data@NoArgsConstructor@AllArgsConstructorpublic static class Foo {    public String name;} /** Test. */@Data@NoArgsConstructor@AllArgsConstructorpublic static class Dummy {    public String name;}

以及另一个对象

@NoArgsConstructor@AllArgsConstructor@Datapublic static class Spec {     public String spec;     public T deserializeTo() throws JsonProcessingException {        var mapper = new ObjectMapper();        return (T) mapper.readValue(spec, Foo.class);    }}

可以看到Spec对象中保存了以上两种类型json序列化后的字符串,并提供了方法将string spec 反序列化成相应的类型,比较理想的方式是在反序列化的方法中能够获取到参数类型 T 的实际类型,理论上运行时Spec类型是确定了,因此T也应该是确定的,但是因为类型擦除,所以实际上获取不到他的类型。

按照以下尝试 通过((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()获取泛型类型,经过测试是获取不到的

 @Test    public void test() throws JsonProcessingException {        var foo = new Foo("foo");        var spec = new Spec(mapper.writeValueAsString(foo));        var deserialized = spec.deserializeTo();        Assertions.assertTrue(deserialized instanceof Foo);    }     @NoArgsConstructor    @AllArgsConstructor    @Data    public static class Spec {         public String spec;         private Class getSpecClass() {            return (Class)                    ((ParameterizedType) getClass().getGenericSuperclass())                            .getActualTypeArguments()[0];        }         public T deserializeTo() throws JsonProcessingException {            var mapper = new ObjectMapper();            System.out.println(spec);            return (T) mapper.readValue(spec, getSpecClass());        }    }

会有以下的错误

java.lang.ClassCastException: class java.lang.Class cannot be cast to class java.lang.reflect.ParameterizedType (java.lang.Class and java.lang.reflect.ParameterizedType are in module java.base of loader 'bootstrap')

有两种办法来绕过这个问题

第一种比较简单,就是在创建spec对象时,直接把类型的class传进来,这样就可以直接使用。

第二种是创建spec的子类中使用这个方法就可以获取泛型的类型

@Datapublic abstract static class AbstractSpec {     public String spec;     public AbstractSpec(String spec) {        this.spec = spec;    }     private Class getSpecClass() {        return (Class)                ((ParameterizedType) getClass().getGenericSuperclass())                        .getActualTypeArguments()[0];    }     public T deserializeTo() throws JsonProcessingException {        var mapper = new ObjectMapper();        System.out.println(spec);        return (T) mapper.readValue(spec, getSpecClass());    }} public static class Spec extends AbstractSpec {    public Spec(String spec) {        super(spec);    }} @Testpublic void test() throws JsonProcessingException {    var foo = new Foo("foo");    var spec = new Spec(mapper.writeValueAsString(foo));    var deserialized = spec.deserializeTo();    Assertions.assertTrue(deserialized instanceof Foo);}

这里spec类就可以顺利的被反序列化。

这个和最开始失败的case的差别就是新增了一个子类,主要的差别是getGenericSuperclass的返回值有差异,非子类的情况下,获取到的是Object。

因此理论上子类Spec的类型信息中,实际上是保存了父类中的类型参数信息的,也就是例子中的Foo. 按照 https://stackoverflow.com/questions/42874197/getgenericsuperclass-in-java-how-does-it-work 的方式,可以查看到Spec类的字节码中有相应的类型信息。

$ javap -verbose ./org/apache/flink/kubernetes/operator/controller/GenericTest\$Spec.class | grep Signature  #15 = Utf8               Signature        Start  Length  Slot  Name   SignatureSignature: #19                          // Lorg/apache/flink/kubernetes/operator/controller/GenericTest$AbstractSpec;

以上就是关于"Java泛型中类型擦除问题怎么解决"这篇文章的内容,相信大家都有了一定的了解,希望小编分享的内容对大家有帮助,若想了解更多相关的知识内容,请关注行业资讯频道。

类型 内容 问题 序列 信息 子类 实际 对象 就是 方法 参数 实际上 差别 文章 方式 理论 知识 篇文章 两个 也就是 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 移动电信网络安全技能 开源环境下的数据库管理 如何登录服务器管理员密码 文件备份服务器管理制度 北大网络安全学院 认识网络安全的重要性 游戏服务器更新有什么好处 服务器节点软件 国泰安数据库 中山大学 云搏网络技术有限公司 青海专升本网络技术基础真题 媒体服务器是不是就是解码器 win7安装远程服务器管理工具 服务器自带地址怎么删除 中国网络安全空间创新创业 sql系统数据库备份 淮南纵横网络技术有限责任公司 奉节网络安全审计系统咨询公司 数据库sql怎么切换中文 深圳橙社网络技术有限公司 网络技术应用教案 沪教版 vs和数据库制作网上书店 宁海安卓软件开发工具 虚拟仿真软件开发待遇 网络安全事件书面检查 网络安全责任制考核自查报告 网络安全考研复试问题 有事有哪几个数据库 软件开发后怎么扩大业务 不传谣不信谣网络安全
0