Java泛型学习-20170818

来源:互联网 发布:分析家免费行情软件 编辑:程序博客网 时间:2024/06/05 21:54

Java泛型学习系列文章:

Java泛型学习-20170816
http://blog.csdn.net/clandellen/article/details/77219824

Java泛型学习-20170817
http://blog.csdn.net/clandellen/article/details/77285616

接着对泛型进行学习,前篇文章,我们学习了泛型与继承之间的关系以及通配符的使用,最后学习了泛型方法的声明和使用,本篇文章将带你学习泛型的擦除与翻译,重要指数爆表,请一定认真再认真的学习,因为此篇文章懂了,泛型的一切知识都基本上Ok啦。注意一下,有些书本上将”< T >”中的T叫类型变量,和笔者这里说的泛型变量是一个意思。

1.泛型的擦除和翻译

有一个问题,你肯定很好奇,泛型类或者泛型方法编译器如何编译的呢?这个问题就是泛型的核心知识点了,一旦你理解了,泛型类或者泛型方法编译的过程,那么对于泛型你基本可以掌握个所以然了。Java的泛型实质上是伪泛型,Java虚拟机里面没有泛型,也就是一个Class文件被加载到虚拟机当中没有泛型变量了,全部被移除了,详细的说应该是被擦除和翻译了,看下面的图片流程:

得到的非泛型的Class被加载到Java虚拟机当中。

那我们看一个例子,看看编译器是如何将一个泛型类擦除翻译成另外一个非泛型的类的,下面是一个泛型类的代码:

public class MyClass<T> {    public T getT(T t){        System.out.println(t);        return t;    }    public <K extends List,V> void shuChu(K k,V v){        System.out.println(k);        System.out.println(v);    }}

擦除替换的时候,泛型变量的声明将会被移除,也就是”<…>”通通会去掉,在使用泛型变量的位置就会被替换成上限的类型,没有指定上限类型的上限类型均为原始类型Object,要是还是不理解上限类型,那么我们来几个例子瞧瞧:

   <K> -->这个泛型的声明没有指定上限类型,所以上限类型为原始的类型Object   <J extends List> -->这个泛型的声明指定了上限类型,所以泛型变量J的上限类型为List   <H extends Person,I> -->这个我就不说了,应该懂了上限类型了吧!

既然有上限类型,那么肯定存在着下限类型,比如:

  < k super Student > -->这个泛型的声明指定的下限类型是Student,意思就是说泛型变量K一定不能为Student的子类

理解了泛型变量的上限类型,那么我们就来说说擦除的规则
1.将泛型变量声明去掉,也就是”<…>”通通去掉
2.所有使用泛型变量的位置被替换成该泛型变量的上限类型

明白了这两点,那么上面的代码如何擦除?我们来分析一下,对于泛型变量T而言,它是类层面的泛型变量,并且它没有指定任何上限类型,那么泛型变量T的声明”< T >”被去掉,在使用了泛型变量T的地方被替换成原始类型Object类,再看看泛型方法shuChu(),它声明了两个泛型变量分别为K和V,K指定了上限类型为List,所以在使用泛型变量T的位置将会被替换成List,而泛型变量V没有指定上限类型,所以泛型变量V的上限类型也是原始类型Object类。所以擦除后的代码如下所示:

public class MyClass{    public Object getT(Object t){        System.out.println(t);        return t;    }    public void shuChu(List k,Object v){        System.out.println(k);        System.out.println(v);    }}

当我使用一下代码使用这个泛型类,有些地方还需要给出一点解释,代码如下:

    MyClass<String> myClass = new MyClass<String>();//1    String str = myClass.getT("ss");//2    myClass.shuChu(new ArrayList<String>(),true);//3

为什么明明看到擦除后的代码中getT()方法返回的是一个Object,在代码2处为什么不需要进行强制转换呢?原来是这样的,在使用一个泛型类的时候啊,如果泛型变量被使用于方法的返回类型的时候,这个方法在被使用的时候,其返回值被自动强制转换成合适的类型。什么意思?比如上面代码中的getT()方法返回类型是泛型变量T的值,在生成MyClass< String >对象的时候,编译器记录了这个String类型,当你调用getT()方法的时候,返回值会被强制转换为String类型,因为getT()方法的返回类型的区域使用了类层面的泛型变量T。在你给泛型变量传递参数值的时候,编译器就已经在方法返回值的地方进行了检测,如果一旦返回值用到了泛型,那么就会为此方法加上一个强制转换,这在Java核心技术卷I中有提到,我截图给你看:

所以,学到现在,你应该可以理解集合泛型的原理了吧!泛型的擦除与翻译相当重要,一次没搞懂没关系,看多次,直到理解为止,理解了笔者所讲的,那就恭喜你你已经成功将Java泛型进行解剖了。

总结泛型的擦除与翻译:
编译器在泛型的擦除与翻译干了以下几件大事:

1.将泛型变量声明去掉,也就是”<…>”通通去掉
2.所有使用泛型变量的位置被替换成该泛型变量的上限类型
3.返回值为泛型变量的方法,编译器会在调用此方法的时插入强制类型转换,让此方法的返回值的类型与泛型变量的值保持一致(object类型强制转换为你传入的泛型变量的参数值对应的类型,例如上述代码2处getT()方法调用时把返回值的类型从Object类型强制转换为String类型)

学完以上内容,你就可以看出Java泛型不过是一颗甜甜的语法糖而已。

原创粉丝点击