如果需要看泛型使用Java泛型
1.什么是泛型擦除
- 因为Java 泛型是1.5版本才引入的,为了向下兼容,其实虚拟机是不支持泛型的,Java里面是伪泛型机制
- Java在编译期就擦除了所有泛型信息,这样Java就不需要产生新的类型到字节码,所有泛型类型最终都是一种类型
2.编译期如何擦除泛型:
1.检查泛型类型,获取目标类型
2.擦除类型变量,替换为限定类型
2.1如果泛型类型的类型变量没有限定,比如<T>,就替换为Object类型为原始类型
2.2如果类型变量是<T extends xxxCalss>,就替换为xxxClass类型为原始类型
2.3如果多个限定<T extends xClass1 & XClass2>,就用第一个xClass1类型为原始类型
3.必要的时候插入类型转换来保存类型安全
4.生成桥接方法,在扩展时保持多态性
3.泛型擦除也会有副作用
1.泛型擦除后替换为Object类型,所以不能传基本数据类型,比如List不能写int类型(List<int>)
2.不能使用instanceof来判断类型,因为是Object嘛
3.类不能声明静态的成员变量,因为泛型参数要创建对象时就确定
等等其他
4.这里放黑马教程的截图,可以在哔哩哔哩上免费观看
5.验证泛型擦除
5.1用反射查看
public class Test<T extends Number> {
T t;
public T getT() {
return t;
}
public void setT(T t) {
this.t = t;
}
public <T extends Number> T show(T t) {
return t;
}
}
/*----------------------------------------------------------*/
public class TestObject<T> {
T t;
public T getT() {
return t;
}
public void setT(T t) {
this.t = t;
}
public <T> T show(T t){
return t;
}
}
/*----------------------------------------------------------*/
//利用反射,获取Test类的类对象
Test<Integer> test = new Test<>();
Class<? extends Test> clazz = test.getClass();
//获取成员变量
Field[] testField = clazz.getDeclaredFields();
for (Field field : testField) {
Log.d(TAG, field.getName() + " : " + field.getType().getSimpleName());
}
Log.d(TAG, "-----------------------------------");
//成员方法
Method[] methods = clazz.getMethods();
for (Method method : methods) {
Log.d(TAG, method.getName() + " : " + method.getReturnType().getSimpleName());
}
Log.d(TAG, "-----------------------------------");
TestObject<Integer> testObject = new TestObject<>();
Class<? extends TestObject> clz = testObject.getClass();
//获取成员变量
Field[] testObjectField = clz.getDeclaredFields();
for (Field field : testObjectField) {
Log.d(TAG, field.getName() + " : " + field.getType().getSimpleName());
}
Log.d(TAG, "-----------------------------------");
//成员方法
Method[] objectMethods = clz.getMethods();
for (Method method : objectMethods) {
Log.d(TAG, method.getName() + " : " + method.getReturnType().getSimpleName());
}
- 我们可以看到 extends Number,反射拿到的类型就是Number,否则就是Object
5.2用字节码查看
-
Android studio 安装ASM Bytecode Viewer就能查看
getT()返回的类型为Number
show()方法类型为Number
getT()返回类型为Object
showT()方法类型为Object
6.验证泛型桥接
6.1用反射查看桥接方法
public interface Info<T> {
T info(T t);
}
public class InfoImpl implements Info<Integer> {
@Override
public Integer info(Integer integer) {
return integer;
}
}
/*----------------------------------------------------------*/
InfoImpl info = new InfoImpl();
Class<InfoImpl> infoClazz = InfoImpl.class;
//获取成员变量
Field[] infoFields = infoClazz.getDeclaredFields();
for (Field field : infoFields) {
Log.d(TAG, field.getName() + " : " + field.getType().getSimpleName());
}
Log.d(TAG, "-----------------------------------");
//成员方法
Method[] infoMethods = infoClazz.getMethods();
for (Method method : infoMethods) {
Log.d(TAG, method.getName() + " : " + method.getReturnType().getSimpleName());
}
- 可以看到info方法有两个
6.2用字节码查看桥接方法
7.参考文章
如果有写的不对,希望大家帮忙指出错误,谢谢!
网友评论