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. hdu 3729 I'm Telling the Truth(二分匹配_ 匈牙利算法)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3729 I'm Telling the Truth Time Limit: 2000/1000 MS ( ...

  2. idea 控制台乱码

    第一步:修改intellij idea配置文件: 找到intellij idea安装目录,bin文件夹下面idea64.exe.vmoptions和idea.exe.vmoptions这两个文件,分别 ...

  3. CentOS7防火墙fiewall用法

    CentOS7与以前常用的CentOS6还是有一些不同之处的,比如在设置开放端口的时候稍许有些不同,常用的iptables命令已经被 firewalld代替.这几天正好有在CentOS7系统中玩Sea ...

  4. Web安全的三个攻防姿势

    原文地址:https://segmentfault.com/a/1190000011601837 作者: zwwill_木羽 关于Web安全的问题,是一个老生常谈的问题,作为离用户最近的一层,我们大前 ...

  5. 转:修改shape的文字

    Sub 修改shape的文字()'' 修改shape的文字 宏' '    ActiveSheet.Shapes.Range(Array("Flowchart: Connector 193& ...

  6. java 1.8 新特性 stream

    并发提升 java 中Stream类似于hadoop中的数据分析的思路,只不过hadoop大,用的是多台机算机的计算生态,而java  stream使用的单台计算机中的多cpu分析一块数据的过程.通过 ...

  7. [转载]FFmpeg完美入门[2] - FFmpeg参数说明

     1 通用选项 -L license -h 帮助 -fromats 显示可用的格式,编解码的,协议的. -f fmt 强迫采用格式fmt -i filename 输入文件 -y 覆盖输出文件 -t d ...

  8. hashCode()与equals()区别

    这两个方法均是超类Object自带的成员方法.Object类是所有Java类的祖先.每个类都使用 Object 作为超类.所有对象(包括数组)都实现这个类的方法.在不明确给出超类的情况下,Java会自 ...

  9. /proc/mounts介绍

    现在的 Linux 系统里一般都有这么三个文件:/etc/fstab,/etc/mtab,和 /proc/mounts,比较容易让人迷惑.简单解释一下. /etc/fstab 是只读不写的,它提供的是 ...

  10. sshd_config OpenSSH SSH 进程配置文件配置说明

    名称 sshd_config – OpenSSH SSH 服务器守护进程配置文件 大纲 /etc/ssh/sshd_config 描述sshd 默认从 /etc/ssh/sshd_config 文件( ...