何为泛型擦除

来源:互联网 发布:java多线程运用场景 编辑:程序博客网 时间:2024/05/23 13:08

何为泛型擦除

        要理解泛型的擦除,首先要知道泛型的产生。

        泛型是JDK1.5才添加到Java中的,也就是说JDK1.5之前是没有泛型这一说的。例如:Comparable接口在JDK1.5之前是如下定义的:

        public interface Comparable {

                public int compareTo(Object o)

        }

        在JDK1.5或之后就采用了泛型,具体如下:

        public interface Comparable<T> {

                public int compareTo(T o)

        }

        Java作为一门程序设计语言,需要保证没有使用泛型的代码能在JDK1.5及以后的VM上运行,也就是兼容性的问题。

        为了解决这种代码的的兼容性,Java提供了泛型擦除(Erasure)。下面先看一个例子:

程序清单1 TestGenericErased.java

import java.util.ArrayList;import java.util.List;/** * @author Administrator * */public class TestGenericErased {public static void main(String[] args) {List<String> list1 = new ArrayList<String>();list1.add("solo");List<Integer> list2 = new ArrayList<Integer>();list2.add(999);System.out.println("-------------------");System.out.println("输出字符串:" + list1);System.out.println("输出整数:" + list2);System.out.println("-------------------");System.out.println(list1.getClass());System.out.println(list2.getClass());System.out.println("-------------------");System.out.println("判断list1和list2两个列表的类是否相同:" + (list1.getClass() == list2.getClass()));}}


运行结果:

-------------------输出字符串:[solo]输出整数:[999]-------------------class java.util.ArrayListclass java.util.ArrayList-------------------判断list1和list2两个列表的类是否相同:true


        上面的代码有两个不同的ArrayList:ArrayList<Integer>和 ArrayList<String>,前一个是保存整数的列表,后一个事保存字符串的列表,是两个具有不同参数化类型的ArrayList。但是通过比较它们的 Class 对象,运行结果输出的是 true。这说明在代码运行过程中,JVM虚拟机将它们视为同一个类:class java.util.ArrayList。

        为什么会是这样的结果呢?编译器做了什么?

        为了解决前面所说的兼容性问题,编译器需要做一些擦除的工作,通俗地说:编译器擦除掉在代码中与泛型类型有关的信息,这样最后生成出来的代码(字节码文件)其实是没有了泛型的代码,也就是说泛型基本上由编译器来实现,由编译器执行类型检查和类型推断,然后在生成字节码之前将其清除掉,虚拟机并不知道也不关心是否存在泛型。这样的话,泛型和非泛型的代码就可以混合运行,保证了代码的兼容性。

        还需要说明的是:在使用泛型时,会有一个对应的类型叫做原生类型(raw type),泛型类型会被擦除到原生类型,例如:前面的代码中,ArrayList<String>()会被擦除到ArrayList,ArrayList<Integer>()被擦除到ArrayList,由于擦除,在虚拟机中无法获得任何类型信息,虚拟机只知道原生类型。

        为了更进一步了解擦除,下面使用DJ Java Decompiler反编译工具对TestGenericErased.java源文件编译后的TestGenericErased.class字节码文件进行反编译,其反编译的代码如下:

程序清单2 TestGenericErased.class反编译后的代码

// Decompiled by DJ v3.12.12.100 Copyright 2015 Atanas Neshkov  Date: 2017/11/18 星期六 17:39:45// Home Page:  http://www.neshkov.com/dj.html - Check often for new version!// Decompiler options: packimports(3) // Source File Name:   TestGenericErased.javaimport java.io.PrintStream;import java.util.ArrayList;import java.util.List;public class TestGenericErased{    public TestGenericErased()    {    }    public static void main(String args[])    {        ArrayList arraylist = new ArrayList();        arraylist.add("solo");        ArrayList arraylist1 = new ArrayList();        arraylist1.add(Integer.valueOf(999));        System.out.println("-------------------");        System.out.println((new StringBuilder()).append("\u8F93\u51FA\u5B57\u7B26\u4E32\uFF1A").append(arraylist).toString());        System.out.println((new StringBuilder()).append("\u8F93\u51FA\u6574\u6570\uFF1A").append(arraylist1).toString());        System.out.println("-------------------");        System.out.println(arraylist.getClass());        System.out.println(arraylist1.getClass());        System.out.println("-------------------");        System.out.println((new StringBuilder()).append("\u5224\u65ADlist1\u548Clist2\u4E24\u4E2A\u5217\u8868\u7684\u7C7B\u662F\u5426\u76F8\u540C\uFF1A").append(arraylist.getClass() == arraylist1.getClass()).toString());    }}


 

        对比程序清单1和程序清单2,在程序清单2中没有了泛型,程序又回到Java泛型出现之前的写法,泛型类型都变回了原生类型ArrayList,具体是:

程序清单1

程序清单2

List<String>

ArrayList

ArrayList<String>()

ArrayList

List<Integer>

ArrayList

ArrayList<Integer>()

ArrayList

 

参考网址:

1.https://www.cnblogs.com/drizzlewithwind/p/6101081.html

2.http://justjavac.iteye.com/blog/1741638

3.http://blog.csdn.net/lonelyroamer/article/details/7868820

4.https://www.cnblogs.com/xltcjylove/p/3671943.html

5.https://www.cnblogs.com/LinkinPark/p/5232980.html

6.http://blog.sina.com.cn/s/blog_7ffb8dd501012ku9.html

7.http://blog.csdn.net/yuhongye111/article/details/39104601

原创粉丝点击