Java泛型类型擦除

      泛型是JDK1.5的一项新增特性,它的本质是参数化类型的应用,也就是说所操作的数据类型被指定为一个参数。这种参数类型可以用在类、接口和方法的创建中,分别称为泛型类、泛型接口和泛型方法。

      泛型技术在C#和Java之中的使用方式看似相同,但实现上却有着根本性的分歧,C#里面泛型无论在程序源代码中,编译后的IL中或是运行期的CLR中,都是切实存在的,List<Integer>和List<String>就是两个不同的类型,它们在系统运行期生成,有自己的虚方法表和类型数据,这种实现称为类型膨胀,基于这种方法实现的泛型称为真实泛型。

      Java语言中的泛型规则则不一样,它只在程序源码中存在,在编译后的字节码文件中,就已经替换为原来的原生类型了,并且在相应的地方插入了强制类型转换的代码,因此对于运行期的Java语言来说,ArrayList<Integer>和ArrayList<String>就是同一个类,Java语言中的泛型实现方法称为类型擦除,基于这种方法实现的泛型称为伪泛型。看如下的代码实例:

public class GenericTest {
    public static void main(String[] args) {
        Map<String, String> map = new HashMap<String, String>();
        map.put("Hello", "上海");
        map.put("Hi", "北京");
        System.out.println(map.get("Hello"));
        System.out.println(map.get("Hi"));
    }
}

      把这段Java代码编译成Class文件,然后再用字节码反编译工具进行反编译后,将会发现泛型都已经不见了,程序又变回了Java泛型出现之前的写法,泛型类型都变回了原生类型。代码清单如下:

public class GenericTest {
    public GenericTest() {
    }
    public static void main(String[] args) {
        HashMap map = new HashMap();
        map.put("Hello", "上海");
        map.put("Hi", "北京");
        System.out.println((String)map.get("Hello"));
        System.out.println((String)map.get("Hi"));
    }
}

    Java通过擦除法来实现泛型丧失了一些泛型思想应有的优雅,例如下面的代码:    

public class GenericTest {
   public void method1(List<String> list){
       System.out.println("Hello World");
   }
   public void method1(List<Integer> list){
       System.out.println("Hello World");
   }
}

     上面的代码是不能编译成功的,因为参数List<String> list和List<Integer> list编译之后都被擦除了,变成了一样的原生类型List<E>,擦除动作到这这两个方法的特征签名变得一模一样。这样就导致了编译错误。

      

猜你喜欢

转载自blog.csdn.net/xzx4959/article/details/79362103