RIGUZ Lee

关于 Java泛型

2017-12-21 / Programing / Java
  1. 1. Bounded Generics
    1. 1.1. Multiple bound
    2. 1.2. Unbounded wildcards
    3. 1.3. Upper bounded wildcards
    4. 1.4. Lower bounded wildcards
  2. 2. Type erase
    1. 2.1. Type erase process
    2. 2.2. Bridge method
  3. 3. Q&A
    1. 3.1. List<?> vs List<Object>
    2. 3.2. extends vs super

泛型是Java1.5之后一个比较有用的特性,有点类似于C++的模板。最简单的一个例子:

有一些可能不是特别常用的Generics,我们来简单看一下。

1. Bounded Generics

1.1. Multiple bound

如果一个类继承了多个接口,是这样的写法:

假如一个方法的泛型参数包含多个Bound,则要这样写了:

1.2. Unbounded wildcards

使用 ? 修饰符可以用作类型转换,List<?> 意味着是一个未知类型的List,可能是List<A> 也可能是List<B>

1.3. Upper bounded wildcards

1.4. Lower bounded wildcards

2. Type erase

2.1. Type erase process

Java的泛型是编译时有效的,在运行时,所有泛型参数会被编译器擦除。擦除的规则如下:

  • 如果参数是有Bound的,则会替换成这个Bound
  • 如果是Unbounded,则会替换成Object

如下所示:

2.2. Bridge method

按照上面的擦除也会带来问题。考虑下面的例子,如果有一个子类:

然后,我们考虑如下的代码:

这里调用setData则会参数类型不能匹配。为了解决这个问题,Java编译器会生成一个Bridge method:

3. Q&A

3.1. List<?> vs List<Object>

It's important to note that List and List<?> are not the same. You can insert an Object, or any subtype of >Object, into a List. But you can only insert null into a List<?>.

3.2. extends vs super

实际上泛型仅仅是为了做一个编译时的检查,从逻辑上确保程序是类型安全的。假设我们有这样的类定义: Object->Parent->T->Child 我们有这样几种写法:

  • List<?> 代表一种未知类型的List,可能是List<Object>,也可能是List<Child>,都可以
  • List<? extends T> 代表T或者T的子类的List,可以是List<T>,也可以是List<Child>
  • List<? super T> 代表T或者T的父类的List,可以是List<T>,List<Parent>,List<Object>

我们有一个事实就是,Child是一定可以转化T或者Parent的,但是一个T不一定能转化成Child,因为可能会是别的子类。 比如我们现在做两个列表的拷贝,

想实现从一个列表拷贝到另一个列表,比如

基于上面说的类的继承的事实,ts/childs显然是可以转化成parents的,但是ts无法确保能转化成childs。因此我们的拷贝方法要这样定义:

因为在desc.set()方法中,需要的是一个能够转化为T的对象的,src中<? extends T> 保证了src中的元素一定是一个T。

See also: