java generic faq_java学习笔记--基础知识--泛型-深入

参考文档:

泛型相关概念和名词

泛型: Generic Type

Generic type && type parameter:    举例: interface List {}, List就是generic type, 而 E 就是 type parameter

parameterized type && type argument: 举例:List stringList;  List就是parameterized type,是List的一个实例,而String则是type argument

Generic type -》 泛型      Type parameter: 泛型形参

Parameterized type -》参数化类型        type argument : 泛型实参

通配符: wildcard

泛型中的通配符分为3类

?- unbound, 没有任何限定的通配符

? extends Class - upper bounded, 上限限定,必须是Class或者Class的子类

? super Class - lower bounded, 下限限定, 必须是Class或者Class的父类

与通配符结合后,Parameterized type也分为3种:

conceret Parameterized type, 例如  List,   中文名就叫 固定参数化类型 吧

unbounded Parameterized type,  例如 List>, 无绑定参数化类型

bounded Parameterized type, 例如 List extends Number>,   List super Integer>,  有绑定参数化类型

类型信息擦除 Type Erasure

泛型仅仅存在于编译期间,JVM是感知不到泛型信息的。 在编译的时候,编译器通过Type Erasure清除Type parameter和Type Argument。

我们先来了解下,编译器怎么处理泛型的代码,2种方式:

Code Specialization: 编译器为每个泛型实例都产生一份代码。 譬如说, 编译器会给 List产生一份代码,也会为List产生一份代码。C++采用这种方式处理Template。

Code Sharing: 编译器对泛型只生成一份唯一的代码, 然后所有的这个泛型的实例都会映射到这个一份唯一的代码上,进行类型检查和必要的类型转换。 java采用是这种方式。

java编译器实现Code Sharing的方法称为 Type Erasure

Type Erasure就是将通过忽略Type parameter和Type argument的方式,将一个泛型实例映射到编译器生成的那份唯一代码上。 怎么映射呢? 其实这很难想明白。

我们可以这样想象一下, Type Erasure就是将Type parameter和Type argument清除,将泛型的代码变成非泛型的普通代码(中间代码),然后编译成字节码(实际上,编译器编译时没有生成中间的代码,而是直接生成了字节码)。

看下图,左边是泛型代码,右边是Type Erasure之后的代码

72d2f5aa94578d538e9516f36d2eceb0.png

Type Erasure的工作步骤如下:

清除泛型定义中的Type parameter:分2步,第一删除Type parameter的定义,也就是 和 >; 第二步将所有的Type parameter替换成leftmost bound,如果没有bound则替换为Object。

清除泛型实例中的Type argument, 例如 List变成 List

添加必要的桥接函数和类型转换代码(这个必要太关键了,想象不出来,编译器咋就能这么聪明!!!)

对照上面的图,我们一起来分析下,Type Erasure具体都做了什么:

上图原始代码中,我用3中颜色的方框进行的标识,绿框是Type parameter, 蓝框是Type Argument, 红框是我自己框的,我觉得是type parameter的定义。

对于Conparable接口,被转换成了一个非泛型接口,unbounded type parameter被转换成了Object。

NumericValue 实现了一个非泛型的接口,编译器此处加入了一个桥接函数,就是字体加粗的那个compareTo函数,因为如果不添加这个函数,相当于NumericValue 没有实现接口。

max函数变成了一个普通函数, bounded type parameter A都被Comparable替换掉了, Iterator变成了Iterator,并添加了类型转换代码。

泛型的类型系统

泛型的引入使得对象之间的关系变得更复杂了,猜测下面例子中,那个是不对的?

[code] List a = new ArrayList();

ArrayList b = new ArrayList();

List extends Number> c = new ArrayList();

List super Number> d = new ArrayList();

List super Integer> e = d;

答案是第二行。

泛型实例之间是否能够认为是父子关系,我们需要从2个层面考虑:

1. 泛型的raw类型之间是否有继承关系。 (List的raw类型是List)

2. 泛型实例中的Type argument是否有超集的关系

当两个泛型实例的Type argument相同时:例如,List  和 ArrayList, 因为List是ArrayList的父类型,所以可以认为List是ArrayList的父类型。

当两个泛型实例的Type argument不相同,而raw类型相同或具有父子关系时,如果type argument 是对方的超集时,才能说是对方的父类。  例如  List extends Number> 和 List extends Integer>,我们可以说前者是后者的父类

总结一下:

A  B

A   B:  如果A和B同类,或者A是B的父类,那么就可以说A 是 B的父类

A

A extends ClassA>     A extends ClassB>: 如果 ? extends ClassA 包括的类的范围是 ? extends ClassB 包括的类的超集,那么可以说  A extends ClassA> 是 A extends ClassB>的父类

泛型数组

只记一句话吧, 我们只能为 unbounded 的泛型实例建立泛型数组,但是这样写啥意义也没有啊。

[code]List>[] b = new List>[10];

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值