Java泛型学习二:擦除
一.开篇
???? 上文http://zy19982004.iteye.com/blog/1976993中提到“NewCollections.map() return Map<Object, Object>, but not? Map<Integer, String>”,为什么呢?对擦除的理解将是对泛型理解的关键。
?
二.擦除的概念
???? 《Thinking in Java》里说道“在泛型代码内部,无法获得任何有关泛型参数类型的信息”。
???? 《Java核心技术》里说道“虚拟机没有泛型类型对象-所有对象都属于普通类”。
package com.jyz.study.jdk.generic;import java.util.ArrayList;import java.util.Arrays;import java.util.HashMap;import java.util.List;import java.util.Map;/** * 在泛型代码内部,无法获得任何有关泛型参数类型的信息 * @author JoyoungZhang@gmail.com * */public class ClassTypeParameters {static class Frob<T>{}static class FrobF<T extends Number>{}static class FrobPM<P,M>{}private static List list1 = new ArrayList();private static List<Integer> list2 = new ArrayList<Integer>();private static Map<Integer, Integer> map1 = new HashMap<Integer, Integer>();static Frob f1 = new Frob();static FrobF<Integer> f2 = new FrobF<Integer>();static FrobPM<Integer, Double> f3 = new FrobPM<Integer, Double>();//Calss.getTypeParameters()将返回一个TypeVariable对象数组//表示有泛型声明所声明的类型参数public static void main(String[] args) {System.out.println(Arrays.toString(list1.getClass().getTypeParameters()));System.out.println(Arrays.toString(list2.getClass().getTypeParameters()));System.out.println(Arrays.toString(map1.getClass().getTypeParameters()));System.out.println(list1.getClass().getSimpleName());System.out.println(list2.getClass().getSimpleName());System.out.println(Arrays.toString(f1.getClass().getTypeParameters()));System.out.println(Arrays.toString(f2.getClass().getTypeParameters()));System.out.println(Arrays.toString(f3.getClass().getTypeParameters()));}}输出结果[E][E][K, V]ArrayListArrayList[T][T][P, M]?三.为什么要使用擦除
???? 核心动机:使得泛型化的客户端代码可以使用非泛型化的类库,非泛型化的客户端代码可以使用泛型化的类库。这个被称为“兼容迁移性”。这也从侧面反应了,前期的设计多么重要,倘若JDK1.0就将泛型纳入其中,必将是Java使用者的一大福音。
?
三.擦除原则
四.擦除的问题
package com.jyz.study.jdk.generic;/** * 1 2字节码相同 * 边界(泛型切入点):对传递进来的值就行额外的编译期检查,并插入对传递出去的值的转型 * @author JoyoungZhang@gmail.com * */public class TestGenericCheckpoint { public static void main(String[] args) {//1GenericHolder<String> gh = new GenericHolder<String>();gh.set("sa");//边界 编译器checkString sa1 = gh.get();//运行期间仍会checkcast//2SimpleHolder sh = new SimpleHolder();sh.set("sa");//编译器不check任何东西String sa2 = (String) sh.get();//运行期间checkcast }}class GenericHolder<T>{ private T object; public void set(T object){this.object = object; } public T get(){return object; }}class SimpleHolder{ private Object object; public void set(Object object){this.object = object; } public Object get(){return this.object; }}?擦除后显式的引用运行时类型的操作都将无法工作,包括转型,instanceof,new。有什么补救措施?可以采用类型标签。?isInstance代替 instanceof;newInstance代替new,注意newInstance需要class对象具有默认构造函数。//Determines if the specified <code>Object</code> is assignment-compatible// * with the object represented by this <code>Class</code>. //This method is// * the dynamic equivalent of the Java language //<code>instanceof</code>// * operator.public native boolean isInstance(Object obj);//Creates a new instance of the class represented by this <tt>Class</tt>// * object.public T newInstance() {...}?