泛型通过类型擦除来实现,类型擦除 java
以前就了解过爪哇泛型的实现是不完整的,最近在做一些代码重构的时候遇到一些爪哇泛型类型擦除的问题,简单的来说,Java泛型中所指定的类型在编译时会将其去除,因此目录和目录在编译成字节码的时候实际上是一样的。因此爪哇岛泛型只能做到编译期检查的功能,运行期间就不能保证类型安全。我最近遇到的一个问题如下:
假设有两个豆类
/**测试. Data @ NoArgsConstructor @ AllArgsConstructorpublic静态类Foo {公共字符串名称} /**测试. Data @ NoArgsConstructor @ AllArgsConstructorpublic静态类虚拟{公共字符串名称}以及另一个对象
@ NoArgsConstructor @ AllArgsConstructor @ data public静态类SpecT { public String spec public T deserialize to()引发JsonProcessingException { var mapper=new object mapper();return (T) mapper.readValue(spec,foo。类);}}可以看到投机对象中保存了以上两种类型数据序列化后的字符串,并提供了方法将字符串规格反序列化成相应的类型,比较理想的方式是在反序列化的方法中能够获取到参数类型英语字母表中第二十个字母的实际类型,理论上运行时投机类型是确定了,因此英语字母表中第二十个字母也应该是确定的,但是因为类型擦除,所以实际上获取不到他的类型。
按照以下尝试通过((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()获取泛型类型,经过测试是获取不到的
@Test public void test()抛出JsonProcessingException { var Foo=new Foo( Foo );var spec=新的spec foo(映射器。writevalueasstring(foo));var deserialid=spec。deserialito();Assertions.assertTrue(反序列化富(中国姓氏)的instance of } @ NoArgsConstructor @ AllArgsConstructor @ Data公共静态类SpecT { public String spec private class t getSpecClass(){ return(clast)((参数化类型)getClass().getGenericSuperclass()).getActualTypeArguments()[0];} public T deserializeTo()抛出JsonProcessingException { var mapper=new object mapper();系统。出去。println(规格);return (T) mapper.readValue(spec,getSpecClass());} }会有以下的错误
Java . lang . classcastexception :类Java。郎。班级不能转换为类Java。郎。反思。参数化类型(Java。郎。班级和Java。郎。反思。参数化类型位于加载程序“自举”的java.base模块中)
有两种办法来绕过这个问题
第一种比较简单,就是在创建投机对象时,直接把类型的班级传进来,这样就可以直接使用。
第二种是创建投机的子类中使用这个方法就可以获取泛型的类型
@Datapublic抽象静态类抽象SPECT {公共字符串spec;公共抽象规范(字符串规范){ this。spec=spec} private clast getSpecClass(){ return(clast)((ParameterizedType)getClass().getGenericSuperclass()).getActualTypeArguments()[0];} public T deserializeTo()抛出JsonProcessingException { var mapper=new object mapper();系统。出去。println(规格);return (T) mapper.readValue(spec,getSpecClass());}}公共静态类投机扩展AbstractSpecFoo { public Spec(String Spec){ super(Spec);}} @Testpublic void test()抛出JsonProcessingException { var Foo=new Foo( Foo );var Spec=新规格(映射器。writevalueasstring(foo));var deserialid=spec。deserialito();Assertions.assertTrue(反序列化富(中国姓氏)的instanceof}这里投机类就可以顺利的被反序列化。
这个和最开始失败的情况的差别就是新增了一个子类,主要的差别是getGenericSuperclass的返回值有差异,非子类的情况下,获取到的是对象。
所以理论上子类Spec的类型信息实际上保存了父类的类型参数信息,也就是例子中的Foo。根据https://stack overflow.com/questions/42874197/getgenericsuperclass-in-Java-how-it-work的方式可以看出,Spec类的字节码中有对应的类型信息。
$ javap -verbose。/org/Apache/flink/kubernetes/operator/controller/generic test $ spec . class grep Signature # 15=Utf8签名起始长度槽名signaturesignature : # 19//Lorg/Apache/flink/kubernetes/operator/generic test $ AbstractSpecLorg/Apache/flink/kubernetes/operator/controller/generic test $ Foo;关于Java泛型中类型擦除的解决方案,本文到此结束。有关Java泛型中类型擦除的更多信息,请搜索以前关于流行IT的文章或继续浏览下面的相关文章。我希望你以后能更多地支持流行音乐!
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。