Java泛型之类型未被擦除
1. 泛型擦除
泛型是在 Jdk1.5 之后引入的,为了使字节码向前兼容,Java编译器会在编译时擦除泛型信息(泛型擦除)。假使有泛型类Xx<T>,对其进行反射并打印类中的泛型方法:
public class Xx<T> {
public void m(T t) {}
public void m(T[] arr) {}
public void m(List<T> list) {}
}
Method[] declaredMethods = Xx.class.getDeclaredMethods();
for (Method declaredMethod : declaredMethods) {
System.out.println(declaredMethod);
}
打印信息如下:
public void Xx.m(java.util.List)
public void Xx.m(java.lang.Object[])
public void Xx.m(java.lang.Object)
2. 桥接方法
假使有类Xx2继承自Xx<String>,则显然Xx2并未覆盖Xx中的两个方法:
1. public void Xx.m(java.lang.Object)
2. public void Xx.m(java.lang.Object[])
public class Xx2 extends Xx<String> {
@Override
public void m(String t) {}
@Override
public void m(String[] arr) {}
@Override
public void m(List<String> list) {}
}
对Xx2进行反射并打印类中的方法:
Method[] declaredMethods = Xx2.class.getDeclaredMethods();
for (Method declaredMethod : declaredMethods) {
System.out.println(declaredMethod);
}
public void Xx2.m(java.util.List)
public void Xx2.m(java.lang.Object[])
public void Xx2.m(java.lang.Object)
public void Xx2.m(java.lang.String[])
public void Xx2.m(java.lang.String)
可见Xx2源码被编译成字节码后,额外生成了两个方法:
1. public void Xx2.m(java.lang.Object)
2. public void Xx2.m(java.lang.Object[])
这两个方法被称为桥接方法。桥接方法覆盖父类中的泛型方法,并在内部调用子类中的具体方法:
public void m(Object t) {
m((String) t);
}
public void m(Object[] arr) {
m((String[]) arr);
}
可以使用Method.isBridge来判断方法是否为桥接方法:
Method[] declaredMethods = Xx2.class.getDeclaredMethods();
for (Method declaredMethod : declaredMethods) {
System.out.println(declaredMethod);
System.out.println(" -isBridge: " + declaredMethod.isBridge());
}
public void Xx2.m(java.util.List)
-isBridge: false
public void Xx2.m(java.lang.Object[])
-isBridge: true
public void Xx2.m(java.lang.Object)
-isBridge: true
public void Xx2.m(java.lang.String[])
-isBridge: false
public void Xx2.m(java.lang.String)
-isBridge: false
3. 获取泛型信息
Java编译器会擦除方法内部的泛型信息:
void m() {
List<String> list = new ArrayList<>();
}
因此,方法内部全部对象的泛型信息将丢失。但Java编译器也在字节码中保留三处泛型信息:
1. 类定义的泛型信息
2. 类中字段的泛型信息
3. 方法参数的泛型信息
Java泛型信息由java.lang.reflect.Type的五个子类进行描述:
1. java.lang.Class(如:java.lang.String)
2. java.lang.reflect.TypeVariable(如:T)
3. java.lang.reflect.WildcardType(如:? extends Comparable)
4. java.lang.reflect.GenericArrayType(如:T[])
5. java.lang.reflect.ParameterizedType(如:List<String>)
3.1 获取类定义上的泛型信息
1. Class.getTypeParameters
TypeVariable<Class<Xx>> typeParameter = Xx.class.getTypeParameters()[0];
System.out.println(typeParameter + ": " + typeParameter.getClass());
打印信息如下:
T: class sun.reflect.generics.reflectiveObjects.TypeVariableImpl
2. Class.getGenericSuperClass / Class.getGenericInterfaces
Type genericSuperclass = Xx2.class.getGenericSuperclass();
System.out.println(genericSuperclass + ": " + genericSuperclass.getClass());
打印信息如下:
Xx<java.lang.String>: class sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl
3.2 类中字段的泛型信息(Field.getGenericType)
List<? extends String> list;
Field list = Xx.class.getDeclaredField("list");
Type genericType = list.getGenericType();
System.out.println(genericType + ": " + genericType.getClass());
打印信息如下:
java.util.List<? extends java.lang.String>: class sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl
3.3 方法参数的泛型信息(Method.getGenericParameterTypes / Method.getGenericReturnType)
Method m = Xx.class.getDeclaredMethod("m", Object[].class);
Type parameterType = m.getGenericParameterTypes()[0];
System.out.println(parameterType + ": " + parameterType.getClass());
打印信息如下:
T[]: class sun.reflect.generics.reflectiveObjects.GenericArrayTypeImpl
Java泛型之类型未被擦除的更多相关文章
- Java泛型:类型擦除
类型擦除 代码片段一 Class c1 = new ArrayList<Integer>().getClass(); Class c2 = new ArrayList<String& ...
- Java泛型之类型擦除
类型擦除 学过C++模板的,在使用Java泛型的时候,会感觉到有点不疑问,例如:(1)无法定义一个泛型数组.无法调用泛型参数对象中对应的方法(当然,通过extends关键字是可以做到,只是比较麻烦): ...
- Java 泛型 通配符类型
Java 泛型 通配符类型 @author ixenos 摘要:限定通配符类型.无限定通配符类型.与普通泛型区别.通配符捕获 通配符类型 通配符的子类型限定(?都是儿孙) <? 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 ...
随机推荐
- discuz2.5登录后台闪退的解决办法
今天突然发现discuz2.5论坛后台进不去,开始以为密码错了,但发现登录后也是闪退.我试着清除浏览器cookie,也换了其他浏览器也没有用,还是上网找找吧! discuz2.5进入后台闪退的原因: ...
- 四. Jmeter--JDBC 请求
一, SQLserver 1.下载 JDBC Driver (sqljdbc_6.0.8112.100_enu.exe) https://www.microsoft.com/en-us/downlo ...
- Ajax请求数据与删除数据后刷新页面
1.ajax异步请求数据后填入模态框 请求数据的按钮(HTML) <a class="queryA" href="javascript:void(0)" ...
- discuz各个目录与文件的作用说明
discuz下面有很多文件夹以及文件,你们都知道他们是做什么的么?肯定不知道了吧.但是我们有经常遇到这些文件,譬如在后台文件校验操作都遇到某些文件被修改,这时候也需要知道这些文件是有什么作用的.今天就 ...
- Android设备相关配置
http://source.android.com/devices/tech/storage/index.html Android supports devices with external sto ...
- 在Linux(CentOS)中安装.netcore SDK
官方链接 :https://dotnet.microsoft.com/download/linux-package-manager/centos/sdk-current 可以直接根据官方链接,选择Li ...
- MySQL数据库的“十宗罪”【转】
今天就给大家列举 MySQL 数据库中最经典的十大错误案例,并附有处理问题的解决思路和方法.希望能给刚入行或数据库爱好者一些帮助,今后再遇到任何报错,我们都可以很淡定地去处理.学习任何一门技术的同时, ...
- 在shell中如何判断字符串是否为有效的IP地址【转】
转自 在shell中如何判断字符串是否为有效的IP地址_echoisecho_新浪博客http://blog.sina.com.cn/s/blog_53a844e50100xxus.html 近来需要 ...
- {%csrf_token%}的作用
<form> {%csrf_token%} </form> 在django中我们需要在templates的form中加入{%csrf_token%}这串内容,它的作用是当我们g ...
- java基础16 捕获、抛出以、自定义异常和 finally 块(以及关键字:throw 、throws)
1.异常的体系 /* ------|Throwable:所有异常和错误的超类 ----------|Error(错误):错误一般用于jvm或者硬件引发的问题,所以我们一般不会通过代码去处理错误的 -- ...