自己之前对泛型的的设计机制了解的不是太多, 也只是停留在去用的一些表面上。但直到笔者老师上了一课后,猛然感觉这部分内容有点生疏,于是拿起核心技术卷重温了一遍泛型的机制,例如泛型擦除机制 等等。写下此文,记录一些理解
直接进入正题
泛型代码和虚拟机
- 首先要明白的就只有一件事, java虚拟机没有泛型对象-------所有对象都属于普通类,接下来你就可以编译器是如何
擦除类型
了
泛型擦除机制
直接先看一段代码
public Class Shoe<T>{
private Double price;
private T Brand;
//
//get and setter and toString
}
- 解释:上面我们定义一个
所谓的泛型类
,但实际上无论何时定义一个泛型类型,编译器都会自动提供一个与其对应的原始类型 (original type), 这个original type
就是 类名去掉钻石表达式,也就是上方的 Shoe 类,所以程序中可能有 shoe,shoe,但是一旦编译擦除后,他们都会被擦除成 Shoe .
public Class Shoe{
private Double price;
private Object Brand;
//
//get and setter and toString
}
// 这就是shoe 类的原始类型
-
新的问题出现
如果编译时会将类型擦除,那么下面的这段代码是不是会引发一些思考?
//main方法内, Nike 为自定义的一个类 Shoe<Nike> shoe = new Shoe<>(); shoe.add(new Nike()); shoe.getFirst().showPair(); //showPair() 为Nike的一个方法,查看耐克所有写鞋
既然泛型已经擦除为
Object
类,.getFirst() 返回的是Object
类,根据之前老师讲的静态动态绑定 ,Object类不含有showPair()方法,按理会报错。实际却不会,why ?转换泛型表达式
调用 shoe.getFirst() 时,编译器会强制插入字节码指令,将
Object
转换 Nike 。下面利用反射机制证明泛型擦除
//在编译时检查泛型,检查完后再将泛型擦除。 ArrayList<Number> array = new ArrayList<>();//他要先检查 array.add(2); Integer a = 2; //反射方式,获取出集合ArrayList类的class文件对象 Class c = array.getClass(); //获取ArrayList.class文件中的方法add Method method = c.getMethod("add",Object.class); //使用invoke运行ArrayList方法add method.invoke(array, 150); method.invoke(array, new HashSet<Integer>()); method.invoke(array, 15000); System.out.println(array);