黑马程序员--04.泛型深入--01【泛型术语基础知识】【泛型 编译器 字节码】

泛型深入--1

      泛型基础知识  泛型和编译器  参数化类型的特点

----------- android培训java培训、java学习型技术博客、期待与您交流! ------------

1.    泛型基础知识

1). 泛型术语

注意,这里面以ArrayList及其泛型为例

(1). 泛型类型

ArrayList<E>:泛型类型

E是类型变量的声明

(2). 类型参数/类型变量

E:称为类型参数或者类型变量

实际使用的时候,E要进行具体化

(3). 参数化 (后) 类型 ----Parameterized Type

整个ArrayList<Integer>称为类型化参数

具体化的类型参数容器类型组合到一起整体类型叫做类型化类型。

(4). 原始类型 ----Raw Type

ArrayList本身称为原始类型。

就是没有引入类型参数的类型。

2). 参数化类型和原始类型的兼容性

(1). 参数化类型引用可以指向一个原始类类型对象

Collection<String> c =new Vector();

(2). 原始类类型引用可以指向一个参数化类型对象

Collection c2 =new Vector<String>();

参数化类型和原始类类型可以双向指向

【结论】无论是哪一种方式兼容,都是给Javac做编译检查的时候使用的。

由于javac编译之后类型擦除的存在,上面两种方式运行起来是一样的。

2.    泛型、编译器和字节码

泛型的应用场景:泛型常常用于集合反射

泛型 编译器字节码文件

(1). 泛型出现的目的

简化了程序的书写 (不用强制类型转换) 和提高了数据的安全性 (将运行期间的类型转换错误移动到编译时期的编译错误)

(2). 泛型擦除

[1]. 擦除的概念编译器对含有泛型的源文件编译完成之后,就对里面的存在泛型的地方进行类型擦除。

[2]. 擦除的结果含有泛型信息.java源文件对应的.class文件不包含任何泛型信息

字节码中对于原来存在泛型的地方,【全部是原始类型,没有任何的参数化类型】

e.g. 对于以下两行代码

ArrayList<String> collection1 =new ArrayList<String>();

ArrayList<Integer> collection2 =new ArrayList<Integer>();

{1}. 编译器知道collection1和collection2之间是有区别的。 collection1中的元素只能是String类行的,而collection2中的元素只能是Integer类行的。

       但是编译器完成编译之后,ArrayList<String> collection1中的<String>和ArrayList<Integer> collection2中的<Integer>会javac进行擦除!!!这样字节码中实际对应的代码是:

ArrayList collection1 =new ArrayList();

ArrayList collection2 =new ArrayList();

所以JVM运行起来的时候,对于collection1和collection2是没有任何类型上的差别。验证如下:

ArrayList<String> collection1 =new ArrayList<String>();

ArrayList<Integer> collection2 =new ArrayList<Integer>();

System.out.println(collection1.getClass().getName());

System.out.println(collection2.getClass().getName());

System.out.println(collection1.getClass()==collection2.getClass());

打印结果:


collection1和collection2的类型全部是 java.util.ArrayList 并且是对应的类型是一份字节码文件[collection1.getClass()==collection2.getClass()返回true]。

可以见到JVM运行时,没有遇到任何泛型类型参数信息。这足以证明编译器删掉了泛型信息。

(3). 函数重载和类型化参数

一个类中的多个函数具有相同的参数个数

[1]. 前面对应参数类型一致

[2]. 仅仅某一个参数类型化参数的时候,这两个方法或者这几个方法原始类型一样仅仅具体化的类型参数不一致

【结论】那么此时这几个函数不能够构成重载的!!!


[3]. 原因分析 ----角度I

擦除的角度分析:由于泛型的具体类型参数被具体化之后,javac仅仅在编译的时候帮助进行阻挡非法输入和省略强制类型转换之后,就会擦除掉参数化类型的具体化的类型参数。这个时候,ArrayList<String>,ArrayList<Integer>全都被擦除成了原始类型ArrayList。这样三个方法就是同名,同参数的三个方法,不是重载,是重复,所以不能存在于同一个类中。

[3]. 原因分析 ----角度II

       反证法:假设这三个方法可以重载,编译通过。现在,在方法外部就可以调用这些方法了。假设: 调用语句是:

new TestV().printColl(new ArrayList(), 1);

由于 原始类型可以和 参数化类型进行 双向指向,那么 new ArrayList()既可以传给ArrayList<String>alS,也可以传给ArrayList<Integer>alT,还可以传给ArrayList al这三个参数所在的方法,到底调用哪个方法?javac没有办法搞定。所以编译报错。这样和前面的假设编译通过矛盾,所以就不能重载。

----------- android培训java培训、java学习型技术博客、期待与您交流! ------------

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值