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

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)

猜你喜欢

转载自blog.csdn.net/qq_33221085/article/details/84292098
今日推荐