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)
上一篇: mysql命令行怎么开启慢查询日志