首先放上运行期反射获取Java泛型类型的相关信息的代码:
import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type;public class Test2 {public static void main(String[] args) {Example<String> example = new Example<String>() {};Class<String> type = example.getType();System.out.println(type); // 输出:class java.lang.String}public static class Example<T> {private Class<T> type;public Example() {// 获取泛型类型信息Type genericType = getClass().getGenericSuperclass();if (genericType instanceof ParameterizedType) {ParameterizedType parameterizedType = (ParameterizedType) genericType;Type[] typeArguments = parameterizedType.getActualTypeArguments();if (typeArguments.length > 0) {type = (Class<T>) typeArguments[0];}}}public Class<T> getType() {return type;}} }
运行结果:
class java.lang.StringProcess finished with exit code 0
Java泛型擦除:在编译阶段泛型类型信息会被擦除,也就是说编译后的字节码中不再包含关于泛型类型的具体信息(这是为了保持与旧的Java版本的兼容性,因为泛型是在Java 5中引入的)。
尽管泛型信息在运行时被擦除了,但是仍然可以通过反射获取泛型的类型信息(上面代码展示)
其实java泛型的类型擦除并不是在class文件中不保存泛型信息,而是在字节码的方法体或者类结构中擦掉了泛型信息,这样做的好处就是在不改变虚拟器的前提下可以引入泛型的特性。
在class文件中,并没有丢弃泛型类型,javac编译的时候专门在字节码中分配一个元数据存放 叫做Signature
Signature属性:出现在类、字段表、方法表结构的属性表中,会为这些属性记录泛型签名信息。
这也就是所谓的“范型擦除不彻底”