首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > 编程 >

Java泛型学习2:擦除

2013-11-20 
Java泛型学习二:擦除一.开篇???? 上文http://zy19982004.iteye.com/blog/1976993中提到“NewCollections.ma

Java泛型学习二:擦除

一.开篇

???? 上文http://zy19982004.iteye.com/blog/1976993中提到“NewCollections.map() return Map<Object, Object>, but not? Map<Integer, String>”,为什么呢?对擦除的理解将是对泛型理解的关键。

?

二.擦除的概念

???? 《Thinking in Java》里说道“在泛型代码内部,无法获得任何有关泛型参数类型的信息”。

???? 《Java核心技术》里说道“虚拟机没有泛型类型对象-所有对象都属于普通类”。

    Java泛型是使用擦除(擦除类型参数,替换为限定类型)来实现的。这意味着当你使用泛型时,泛型类型只有在静态类型检查期间才出现,在此之后,任何具体的类型信息都被擦除,你唯一知道的就是你在使用一个对象。因此List<String>和List<Integer>在运行时是相同的类型,这两种类型都被擦除为它们的原生类型List。一个例子,看看运行时,类型参数是什么样子。你能够发现的则是用作参数占位符的标识符,这些对我们没什么用。
    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使用者的一大福音。

?

三.擦除原则

    无限定的类型参数将被替换为Object。比喻List<T> T是无限定的,被替换为Object。有限定的类型参数将被替换为第一个类型参数。比喻List<T extends Comparable & Serializable>,T被替换为Comparable,也称T被擦除到了Comparable。

四.擦除的问题

    既然擦除了类型参数的信息,那编译器是怎么确保方法或类中使用的类型的内部一致性呢?下面这个例子1和2产生的字节码是相同的,一方面验证了上面说的擦除原则;另外一方面说明了泛型工作的地方,称之为边界,在边界处,对传递进来的值就行额外的编译器检查,并插入对传递出去值的转型。?
    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() {...}
    ?

热点排行