欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

java泛型的理解,和为什么擦出后,还可以得到

程序员文章站 2022-03-13 12:04:12
...

java泛型的理解,和为什么擦出后,还可以得到

开篇

泛型的使用和例子不说了,太多同类型的文章,自己搜搜,本文主要说
  • 泛型的来源和影响
  • 泛型擦除
  • 泛型擦除了,为什么反射时还可以得到

泛型的来源和影响

在1.5之前没有泛型的只有class,所有的类都是class,也就是原始类型,我们统一定义了一个class类进行抽象,class类的一个具体对象就是一个类,后面有了泛型,超出了原始类型的定义,我们给class增加了4个平级的类型,他们是,1)参数化类型,就是用了泛型的类。2)类型变量类型,就是泛型里面的那个类型变量。3)泛型表达式类型 4)参数化泛型数组类型。这些都是和原始类型平齐的。
但是jvm只可以处理class原始类型,这个是java一开始就定义好的,如果要改的话,就是要在jvm中增加4中字节码文件,对于jvm改的太大,所以我们不改,在javac编译阶段做兼容。这个也就是为什么我们说java的泛型是伪泛型,因为jvm并不支持泛型

泛型擦除

泛型擦除,就是在编译阶段,把我们写的泛型转化为jvm所支持的原始类型,也就是class类型,并且保持语法不变。这个中间过程很复杂。网上专门解释的文章很多。记住就是jvm不认识我们书写的泛型,javac要做一层转化。这个也就是意味着我们在jvm中,也就是在运行中执行的代码,没有泛型的代码。

泛型擦除了,为什么反射时还可以得到

我们在上面说的泛型既然被擦除了,为什么反射时还可以得到我们书写的泛型呢,这个我找了很多资料才发现,为了方便反射操作,我们在java中定义了一个顶层接口 type他有

  • ParameterizedType: 表示一种参数化的类型,比如Collection
  • GenericArrayType: 表示一种元素类型是参数化类型或者类型变量的数组类型
  • TypeVariable: 是各种类型变量的公共父接口
  • WildcardType: 代表一种通配符类型表达式,比如?, ? extends Number, ? superInteger【wildcard是一个单词:就是“通配符”】

就是我们用class类型表示我们上面说的和原始类型平齐的4种类型,方便我们反射的时候使用,获得泛型的数据。下面我们来回答上面的问题
最后我看资料发现原来javac在编译的时候,确实在代码上把泛型都转化为原始类型了,也就是实现了擦除,要不然也运行不了,但是对于类,方法和属性的泛型(方法体内部除外)。javac编译的时候专门在字节码中分配一个元数据存放 叫做Signature。存放我们泛型信息,方便反射可以得到

import java.util.List;  
import java.util.Map;  
  
public class GenericClass<T> {                // 1  
    private List<T> list;                     // 2  
    private Map<String, T> map;               // 3  
      
    public <U> U genericMethod(Map<T, U> m) { // 4  
        return null;  
    }  
} 

//字节码
private java.util.Map map;  
  Signature: Ljava/util/Map;  
  Signature: length = 0x2  
   00 0A 
//字节码
const #10 = Asciz       Ljava/util/Map<Ljava/lang/String;TT;>;;  

我下面贴几个比较好的,对我有帮助的链接

[添加链接描述](http://www.cnblogs.com/mylove7/articles/5811748.html)
[添加链接描述](http://rednaxelafx.iteye.com/blog/586212)
相关标签: 泛型