夏眠鱼

Oct 18, 2017

Java 泛型-泛型类型

泛型类型(Generic Type)是带类型参数的类或接口。下面我们通过 Box 类来论述什么是泛型类型。

简单的 Box

1
2
3
4
5
6
7
8
9
10
11
public class Box {
private Object object;

public void set(Object object) {
this.object = object;
}

public Object get() {
return object;
}
}

由于 box 接收或返回一个 Object 对象,你可以传入任何你想要的非基本类型,因此在编译阶段无法判断 box 的使用情况。下面的例子在运行时会发生 ClassCastException 错误。

1
2
3
Box box = new Box();
box.set("hello worlds");
int result = (Integer) box.get();

泛型版本的 Box

1
2
3
4
5
6
7
8
9
10
11
public class Box<T> {
private T t;

public void set(T t) {
this.t = t;
}

public T get() {
return T;
}
}

可以看到,所有的 Object 都被替换成 T。我们称 T 为类型参数或类型变量,它可以是任何的非基本类型:类、接口、数组、甚至是类型参数。

根据上面的例子,我们可以得出泛型类定义的语法:
class name<T1, T2, ..., Tn> {/* ... */}

用尖括号(<>)分割的类型参数,遵循类名。泛型接口的定义和泛型类相似。

类型参数的命名惯例

按照惯例,类型参数的命名是单个大写字母,这样可以很好地区分类型参数和普通类或接口。

最常用的类型参数如下:

  • E - Element
  • K - Key
  • V - Value
  • T - Type
  • N - Number
  • S,U,V etc. - 2nd, 3rd, 4th types

泛型类型的调用和实例化

还是以上面的 Box 为例,Box 的调用和实例化如下:

1
2
3
4
5
// 实例化
Box<Integer> box = new Box<Integer>();

// 调用 box 的 get 方法
int result = box.get();

棱形

在 Java SE 7 和 Java SE 7 之后,你可以用一个空的类型参数(一对尖括号:<>)来替换泛型类的构造,只要编译器可以确定或者推断出上下文中的类型参数。这对尖括号叫做棱形。例如,你可以使用下面的语句创建一个 Box 示例:

1
Box<Integer> integerBox = new Box<>();

更多关于棱形和类型推断,请查看 Java 泛型-类型推断

Type Paramemter 和 Type Argument

Type Parameter 和 Type Argument 在中文上都是叫类型参数,很多开发者容易认为是同一个概念,其实它们是有区别的。在编写代码时,为了创建参数化类型,可以提供类型参数(Type Argument)。因此,Box<T> 中的 T 是一个 Type Paramemter,而 Box<Integer> 的 Integer 是一个 Type Argument。

参数化类型

List<String> 这种带类型参数的类型,我们称为参数化类型。泛型的实例化也支持参数化类型。如:

1
2
3
4
5
// 实例化
Box<List<Integer>> box = new Box<List<Integer>>();

// 调用 box 的 get 方法
List<Integer> results = box.get();
OLDER > < NEWER