# 精美印刷品

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

## 泛型类由其所有调用共享

以下代码片段打印什么？

```
List <String> l1 = new ArrayList<String>();
List<Integer> l2 = new ArrayList<Integer>();
System.out.println(l1.getClass() == l2.getClass());

```

你可能想说`false`，但你错了。它打印`true`，因为泛型类的所有实例都具有相同的运行时类，而不管它们的实际类型参数如何。

实际上，使类具有通用性的原因在于它对所有可能的类型参数具有相同的行为;可以将同一类视为具有许多不同类型。

因此，类的静态变量和方法也在所有实例之间共享。这就是为什么在静态方法或初始化程序中或在静态变量的声明或初始化程序中引用类型声明的类型参数是非法的。

## 演员和 InstanceOf

泛型类在其所有实例之间共享这一事实的另一个含义是，询问实例是否是泛型类型的特定调用的实例通常是没有意义的：

```
Collection cs = new ArrayList<String>();
// Illegal.
if (cs instanceof Collection<String>) { ... }

```

同样，演员如

```
// Unchecked warning,
Collection<String> cstr = (Collection<String>) cs;

```

给出一个未经检查的警告，因为这不是运行时系统要检查的东西。

类型变量也是如此

```
// Unchecked warning. 
<T> T badCast(T t, Object o) {
    return (T) o;
}

```

运行时不存在类型变量。这意味着它们在时间和空间上都不会产生性能开销，这很好。不幸的是，这也意味着你无法在演员阵容中可靠地使用它们。

## 数组

数组对象的组件类型可能不是类型变量或参数化类型，除非它是（无界）通配符类型。您可以声明其元素类型为类型变量或参数化类型的数组 _ 类型 _ ，但不是数组 _ 对象 _。

这很烦人，可以肯定。这种限制是必要的，以避免以下情况：

```
// Not really allowed.
List<String>[] lsa = new List<String>[10];
Object o = lsa;
Object[] oa = (Object[]) o;
List<Integer> li = new ArrayList<Integer>();
li.add(new Integer(3));
// Unsound, but passes run time store check
oa[1] = li;

// Run-time error: ClassCastException.
String s = lsa[1].get(0);

```

如果允许参数化类型的数组，则前一个示例将在没有任何未经检查的警告的情况下进行编译，但在运行时仍然失败。我们将类型安全作为仿制药的主要设计目标。特别是，如果使用 `javac -source 1.5` 编译整个应用程序而没有未经检查的警告，该语言可以保证**，它是类型安全的**。

但是，您仍然可以使用通配符数组。前面代码的以下变体放弃了使用数组对象和元素类型参数化的数组类型。因此，我们必须明确地转换为从阵列中获取`String`。

```
// OK, array of unbounded wildcard type.
List<?>[] lsa = new List<?>[10];
Object o = lsa;
Object[] oa = (Object[]) o;
List<Integer> li = new ArrayList<Integer>();
li.add(new Integer(3));
// Correct.
oa[1] = li;
// Run time error, but cast is explicit.
String s = (String) lsa[1].get(0);

```

在导致编译时错误的下一个变体中，我们避免创建其元素类型已参数化的数组对象，但仍使用具有参数化元素类型的数组类型。

```
// Error.
List<String>[] lsa = new List<?>[10];

```

类似地，尝试创建元素类型为类型变量的数组对象会导致编译时错误：

```
<T> T[] makeArray(T t) {
    return new T[100]; // Error.
}

```

由于类型变量在运行时不存在，因此无法确定实际的数组类型。

解决这些限制的方法是使用类文字作为运行时类型标记，如下一节[类文字作为运行时类型标记](literals.html)中所述。