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泛型之类型未被擦除的更多相关文章

  1. Java泛型:类型擦除

    类型擦除 代码片段一 Class c1 = new ArrayList<Integer>().getClass(); Class c2 = new ArrayList<String& ...

  2. Java泛型之类型擦除

    类型擦除 学过C++模板的,在使用Java泛型的时候,会感觉到有点不疑问,例如:(1)无法定义一个泛型数组.无法调用泛型参数对象中对应的方法(当然,通过extends关键字是可以做到,只是比较麻烦): ...

  3. Java 泛型 通配符类型

    Java 泛型 通配符类型 @author ixenos 摘要:限定通配符类型.无限定通配符类型.与普通泛型区别.通配符捕获 通配符类型 通配符的子类型限定(?都是儿孙) <? extends ...

  4. java 泛型的类型擦除和桥方法

    oracle原文地址:https://docs.oracle.com/javase/tutorial/java/generics/erasure.html 在Java中,泛型的引入是为了在编译时提供强 ...

  5. Java泛型-类型擦除

    一.概述 Java泛型在使用过程有诸多的问题,如不存在List<String>.class, List<Integer>不能赋值给List<Number>(不可协变 ...

  6. 转:有关Java泛型的类型擦除(type erasing)

    转载自:拈花微笑 自从Java 5引入泛型之后,Java与C++对于泛型不同的实现的优劣便一直是饭后的谈资.在我之前的很多training中,当讲到Java泛型时总是会和C++的实现比较,一般得出的结 ...

  7. java 泛型的类型擦除与桥方法

    泛型类 --代码参考:java核心技术 卷1 第十版 public class Pair<T> { private T first; private T second; //构造器 pub ...

  8. JAVA 泛型之类型擦除

    ★ 泛型是 JDK 1.5 版本引进的概念,之前是没有泛型的概念的,但泛型代码能够很好地和之前版本的代码很好地兼容. CollectionTest.java ---编译成CollectionTest. ...

  9. Java泛型的类型擦除

    package com.srie.testjava; import java.util.ArrayList; import java.util.List; public class TestGener ...

随机推荐

  1. c语言学习笔记.关键字.存储类型关键字等

    关键字const 1.修饰变量. 修饰的对象为常量,只读. 2.修饰指针. const 也可以和指针变量一起使用,这样可以限制指针变量本身,也可以限制指针指向的数据. const 离变量名近就是用来修 ...

  2. JSON.stringify()——JS转JSON字符串

    JSON.stringify() JSON 通常用于与服务端交换数据. 在向服务器发送数据时一般是字符串. 我们可以使用 JSON.stringify() 方法将 JavaScript 对象转换为字符 ...

  3. sqlmap tamper编写

    #!/usr/bin/env python """ Copyright (c) 2006-2017 sqlmap developers (http://sqlmap.or ...

  4. loadrunner 测试问题汇总

    1.关于Error -27791: Error -27790:Error -27740:        错误如下:        Action.c(198): Error -27791: Server ...

  5. HTML标签学习之路-001

    1.html的注释 <!--这里是注释内容--> <!--代表注释内容的开始 -->代表注释内容结束 注释部分,不会被浏览器输出,只是作为代码的说明,供开发者查阅 2.HTML ...

  6. webstrom 使用git

    1.首先进入码云创建项目 2.创建成功,复制https地址,打开webstrom,选择git,填入https的地址 3.下载完成,打开项目,新建一个测试测HTML文件,点击右键,选择git,再选择ad ...

  7. PHP--- JSON和数组的转换

    一.json_encode() <?php $arr =array ('a'=>1,'b'=>2,'c'=>3,'d'=>4,'e'=>5); echo json_ ...

  8. jsonpath for js

    /** * @license * JSONPath 0.8.0 - XPath for JSON * * Copyright (c) 2007 Stefan Goessner (goessner.ne ...

  9. CPU运行时间——time

    用途说明time命令常用于测量一个命令的运行时间,注意不是用来显示和修改系统时间的(这是date命令干的事情).但是今天我通过查看time命令的手册页,发现它能做的不仅仅是测量运行时间,还可以测量内存 ...

  10. HDU 4300 Clairewd’s message(KMP+思维)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4300 题目大意:题目大意就是给以一段字符xxxxzzz前面x部分是密文z部分是明文,但是我们不知道是从 ...