# 泛型类型

> 原文： [https://docs.oracle.com/javase/tutorial/java/generics/types.html](https://docs.oracle.com/javase/tutorial/java/generics/types.html)

_ 泛型类型 _ 是通过类型参数化的泛型类或接口。以下 `Box` 类将被修改以演示该概念。

## 一个简单的盒子类

首先检查对任何类型的对象进行操作的非泛型 `Box` 类。它只需要提供两种方法：`设置`，它将一个对象添加到框中，`获取`，它检索它：

```
public class Box {
    private Object object;

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

```

由于它的方法接受或返回`对象`，所以只要它不是原始类型之一，您就可以随意传入任何内容。在编译时无法验证类的使用方式。代码的一部分可能会在框中放置 `Integer` 并期望从中获取 `Integer` ，而代码的另一部分可能错误地传入 `String` ，导致运行时错误。

## Box 类的通用版本

_ 泛型类 _ 使用以下格式定义：

```
class name<T1, T2, ..., Tn> { /* ... */ }

```

由尖括号（`&lt;&gt;` ）分隔的类型参数部分遵循类名。它指定 _ 类型参数 _（也称为 _ 类型变量 _） `T1` ， `T2` ，......和 `Tn` ]。

要更新 `Box` 类以使用泛型，您可以通过将代码“ `public class Box` ”更改为“ `public class Box&lt”来创建 _ 泛型类型声明 _ ; T&gt;` “。这引入了类型变量 `T` ，可以在类中的任何地方使用。

通过此更改， `Box` 类变为：

```
/**
 * Generic version of the Box class.
 * @param <T> the type of the value being boxed
 */
public class Box<T> {
    // T stands for "Type"
    private T t;

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

```

如您所见，`对象`的所有出现都被 `T` 取代。类型变量可以是您指定的任何**非原始**类型：任何类类型，任何接口类型，任何数组类型，甚至是其他类型变量。

可以应用相同的技术来创建通用接口。

## 键入参数命名约定

按照惯例，类型参数名称是单个大写字母。这与你已经知道的变量[命名](../nutsandbolts/variables.html#naming)约定形成鲜明对比，并且有充分的理由：如果没有这种约定，很难区分类型变量和普通类或接口名称之间的区别。

最常用的类型参数名称是：

*   E - Element（Java Collections Framework 广泛使用）
*   K - 钥匙
*   N - 数字
*   T 型
*   V - 价值
*   S，U，V 等 - 第 2，第 3，第 4 类型

您将在整个 Java SE API 和本课程的其余部分中看到这些名称。

要从代码中引用通用 `Box` 类，必须执行 _ 泛型类型调用 _，它将 `T` 替换为某些具体值，例如`整数`：

```
Box<Integer> integerBox;

```

您可以将泛型类型调用视为与普通方法调用类似，但不是将参数传递给方法，而是在这种情况下传递 _ 类型参数 _ - `Integer` - 到 `Box` 类本身。

* * *

**Type Parameter and Type Argument Terminology:** Many developers use the terms "type parameter" and "type argument" interchangeably, but these terms are not the same. When coding, one provides type arguments in order to create a parameterized type. Therefore, the `T` in `Foo<T>` is a type parameter and the `String` in `Foo<String> f` is a type argument. This lesson observes this definition when using these terms.

* * *

与任何其他变量声明一样，此代码实际上不会创建新的 `Box` 对象。它简单地声明 `integerBox` 将保持对 `Integer` 的“ `Box` ”的引用，这是 `Box&lt; Integer&gt;` 被阅读。

泛型类型的调用通常称为 _ 参数化类型 _。

要实例化此类，像往常一样使用 `new` 关键字，但放置`&lt; Integer&gt;类名和括号之间的`：

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

```

在 Java SE 7 及更高版本中，只要编译器可以确定或推断类型参数，就可以用一组空的类型参数（&lt;&gt;）替换调用泛型类的构造函数所需的类型参数。上下文。这对尖括号&lt;&gt;非正式地称为 _ 钻石 _。例如，您可以创建 `Box&lt; Integer&gt;的实例。` ，声明如下：

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

```

有关菱形表示法和类型推断的更多信息，请参见[类型推断](genTypeInference.html)。

如前所述，泛型类可以有多个类型参数。例如，通用 `OrderedPair` 类，它实现了通用 `Pair` 接口：

```
public interface Pair<K, V> {
    public K getKey();
    public V getValue();
}

public class OrderedPair<K, V> implements Pair<K, V> {

    private K key;
    private V value;

    public OrderedPair(K key, V value) {
	this.key = key;
	this.value = value;
    }

    public K getKey()	{ return key; }
    public V getValue() { return value; }
}

```

以下语句创建 `OrderedPair` 类的两个实例：

```
Pair<String, Integer> p1 = new OrderedPair<String, Integer>("Even", 8);
Pair<String, String>  p2 = new OrderedPair<String, String>("hello", "world");

```

代码， `new OrderedPair&lt; String，Integer&gt;` ，将 `K` 实例化为`串`和 `V` 作为`整数`。因此， `OrderedPair` 的构造函数的参数类型分别是 `String` 和 `Integer` 。由于[自动装箱](../data/autoboxing.html)，将`字符串`和 `int` 传递给该类是有效的。

如 [The Diamond](#diamond) 中所述，因为 Java 编译器可以从声明 `OrderedPair&lt; String，Integer&gt;中推断 `K` 和 `V` 类型。` ，这些陈述可以使用钻石符号缩短：

```
OrderedPair<String, Integer> p1 = new OrderedPair<>("Even", 8);
OrderedPair<String, String>  p2 = new OrderedPair<>("hello", "world");

```

要创建通用接口，请遵循与创建泛型类相同的约定。

## 参数化类型

您还可以用参数化类型（即 `List&lt; String&gt;` ）替换类型参数（即 `K` 或 `V` ）。例如，使用 `OrderedPair&lt; K，V&gt;` 示例：

```
OrderedPair<String, Box<Integer>> p = new OrderedPair<>("primes", new Box<Integer>(...));

```