Documentation

The Java™ Tutorials
Hide TOC
The Fine Print精美的印刷品
Trail: Bonus
Lesson: Generics

The Fine Print精美的印刷品

A Generic Class is Shared by All Its Invocations泛型类由其所有调用共享

What does the following code fragment print?下面的代码片段打印什么?

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

You might be tempted to say false, but you'd be wrong. 你可能想说false,但你错了。It prints true, because all instances of a generic class have the same run-time class, regardless of their actual type parameters.它打印为true,因为泛型类的所有实例都具有相同的运行时类,而不管它们的实际类型参数如何。

Indeed, what makes a class generic is the fact that it has the same behavior for all of its possible type parameters; the same class can be viewed as having many different types.事实上,类之所以具有泛型性,是因为它对所有可能的类型参数都具有相同的行为;同一类可以被视为有许多不同的类型。

As consequence, the static variables and methods of a class are also shared among all the instances. 因此,类的静态变量和方法也在所有实例之间共享。That is why it is illegal to refer to the type parameters of a type declaration in a static method or initializer, or in the declaration or initializer of a static variable.这就是为什么在静态方法或初始值设定项中,或在静态变量的声明或初始值设定项中引用类型声明的类型参数是非法的。

Casts and InstanceOfCasts和InstanceOf

Another implication of the fact that a generic class is shared among all its instances, is that it usually makes no sense to ask an instance if it is an instance of a particular invocation of a generic type:泛型类在其所有实例之间共享这一事实的另一个含义是,询问实例是否是泛型类型的特定调用的实例通常没有意义:

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

similarly, a cast such as类似地,强制转换如

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

gives an unchecked warning, since this isn't something the runtime system is going to check for you.给出未经检查的警告,因为这不是运行时系统将为您检查的内容。

The same is true of type variables类型变量也是如此

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

Type variables don't exist at run time. 类型变量在运行时不存在。This means that they entail no performance overhead in either time nor space, which is nice. 这意味着它们在时间和空间上都不会带来性能开销,这很好。Unfortunately, it also means that you can't reliably use them in casts.不幸的是,这也意味着您无法在强制转换中可靠地使用它们。

Arrays数组

The component type of an array object may not be a type variable or a parameterized type, unless it is an (unbounded) wildcard type.数组对象的组件类型不能是类型变量或参数化类型,除非它是(无界)通配符类型。You can declare array types whose element type is a type variable or a parameterized type, but not array objects.可以声明其元素类型为类型变量或参数化类型的数组类型,但不能声明数组对象。

This is annoying, to be sure. 当然,这很烦人。This restriction is necessary to avoid situations like:这一限制对于避免以下情况是必要的:

// 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);

If arrays of parameterized type were allowed, the previous example would compile without any unchecked warnings, and yet fail at run-time. 如果允许使用参数化类型的数组,那么前面的示例将在编译时没有任何未检查的警告,但在运行时失败。We've had type-safety as a primary design goal of generics. 我们将类型安全作为泛型的主要设计目标。In particular, the language is designed to guarantee that if your entire application has been compiled without unchecked warnings using javac -source 1.5, it is type safe.特别是,该语言旨在保证,如果使用javac-source 1.5编译的整个应用程序没有未经检查的警告,那么它是类型安全的。

However, you can still use wildcard arrays. 但是,您仍然可以使用通配符数组。The following variation on the previous code forgoes the use of both array objects and array types whose element type is parameterized. 前面代码的以下变体放弃了使用数组对象和元素类型参数化的数组类型。As a result, we have to cast explicitly to get a String out of the array.因此,我们必须显式强制转换才能从数组中获取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);

In the next variation, which causes a compile-time error, we refrain from creating an array object whose element type is parameterized, but still use an array type with a parameterized element type.在导致编译时错误的下一个变体中,我们避免创建元素类型为参数化的数组对象,但仍然使用带有参数化元素类型的数组类型。

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

Similarly, attempting to create an array object whose element type is a type variable causes a compile-time error:类似地,尝试创建元素类型为类型变量的数组对象会导致编译时错误:

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

Since type variables don't exist at run time, there is no way to determine what the actual array type would be.由于类型变量在运行时不存在,因此无法确定实际的数组类型。

The way to work around these kinds of limitations is to use class literals as run time type tokens, as described in the next section, Class Literals as Runtime-Type Tokens.解决这些限制的方法是使用类文本作为运行时类型标记,如下一节,“类文本作为运行时类型标记”中所述。


Previous page: Interoperating with Legacy Code
Next page: Class Literals as Runtime-Type Tokens