The Java Tutorials have been written for JDK 8.Java教程是为JDK 8编写的。Examples and practices described in this page don't take advantage of improvements introduced in later releases and might use technology no longer available.本页中描述的示例和实践没有利用后续版本中引入的改进,并且可能使用不再可用的技术。See Java Language Changes for a summary of updated language features in Java SE 9 and subsequent releases.有关Java SE 9及其后续版本中更新的语言特性的摘要,请参阅Java语言更改。
See JDK Release Notes for information about new features, enhancements, and removed or deprecated options for all JDK releases.有关所有JDK版本的新功能、增强功能以及已删除或不推荐的选项的信息,请参阅JDK发行说明。
The section Type Erasure discusses the process where the compiler removes information related to type parameters and type arguments. 类型擦除部分讨论编译器删除与类型参数和类型参数相关的信息的过程。Type erasure has consequences related to variable arguments (also known as varargs ) methods whose varargs formal parameter has a non-reifiable type. 类型擦除的后果与变量参数(也称为varargs)方法有关,这些方法的varargs形式参数具有不可重新定义的类型。See the section Arbitrary Number of Arguments in Passing Information to a Method or a Constructor for more information about varargs methods.有关varargs方法的更多信息,请参阅向方法或构造函数传递信息的任意参数数量部分。
This page covers the following topics:本页涵盖以下主题:
A reifiable type is a type whose type information is fully available at runtime. 可重新定义类型是其类型信息在运行时完全可用的类型。This includes primitives, non-generic types, raw types, and invocations of unbound wildcards.这包括原语、非泛型类型、原始类型和未绑定通配符的调用。
Non-reifiable types are types where information has been removed at compile-time by type erasure — invocations of generic types that are not defined as unbounded wildcards. 不可重写类型是指在编译时通过类型擦除删除信息的类型—调用未定义为无界通配符的泛型类型。A non-reifiable type does not have all of its information available at runtime. 不可恢复类型在运行时没有其所有信息可用。Examples of non-reifiable types are List<String> and List<Number>; the JVM cannot tell the difference between these types at runtime. 不可恢复类型的示例有List<String>和List<Number>;JVM在运行时无法区分这些类型之间的差异。As shown in Restrictions on Generics, there are certain situations where non-reifiable types cannot be used: in an instanceof expression, for example, or as an element in an array.如泛型限制中所示,在某些情况下不能使用不可重新定义的类型:例如,在instanceof表达式中,或作为数组中的元素。
Heap pollution occurs when a variable of a parameterized type refers to an object that is not of that parameterized type. 当参数化类型的变量引用非该参数化类型的对象时,会发生堆污染。This situation occurs if the program performed some operation that gives rise to an unchecked warning at compile-time. 如果程序执行的某些操作在编译时引起未检查的警告,则会发生这种情况。An unchecked warning is generated if, either at compile-time (within the limits of the compile-time type checking rules) or at runtime, the correctness of an operation involving a parameterized type (for example, a cast or method call) cannot be verified. 如果在编译时(在编译时类型检查规则的限制范围内)或在运行时无法验证涉及参数化类型(例如,强制转换或方法调用)的操作的正确性,则会生成未经检查的警告。For example, heap pollution occurs when mixing raw types and parameterized types, or when performing unchecked casts.例如,当混合原始类型和参数化类型时,或者在执行未经检查的强制转换时,会发生堆污染。
In normal situations, when all code is compiled at the same time, the compiler issues an unchecked warning to draw your attention to potential heap pollution. 在正常情况下,当所有代码同时编译时,编译器会发出未经检查的警告,提醒您注意潜在的堆污染。If you compile sections of your code separately, it is difficult to detect the potential risk of heap pollution. 如果单独编译代码部分,则很难检测堆污染的潜在风险。If you ensure that your code compiles without warnings, then no heap pollution can occur.如果确保代码在编译时没有警告,则不会发生堆污染。
Generic methods that include vararg input parameters can cause heap pollution.包含vararg输入参数的通用方法可能导致堆污染。
Consider the following ArrayBuilder class:考虑下面的ArrayBuilder类:
public class ArrayBuilder { public static <T> void addToList (List<T> listArg, T... elements) { for (T x : elements) { listArg.add(x); } } public static void faultyMethod(List<String>... l) { Object[] objectArray = l; // Valid objectArray[0] = Arrays.asList(42); String s = l[0].get(0); // ClassCastException thrown here } }
The following example, HeapPollutionExample uses the ArrayBuiler class:以下示例HeappolutionExample使用ArrayBuilder类:
public class HeapPollutionExample { public static void main(String[] args) { List<String> stringListA = new ArrayList<String>(); List<String> stringListB = new ArrayList<String>(); ArrayBuilder.addToList(stringListA, "Seven", "Eight", "Nine"); ArrayBuilder.addToList(stringListB, "Ten", "Eleven", "Twelve"); List<List<String>> listOfStringLists = new ArrayList<List<String>>(); ArrayBuilder.addToList(listOfStringLists, stringListA, stringListB); ArrayBuilder.faultyMethod(Arrays.asList("Hello!"), Arrays.asList("World!")); } }
When compiled, the following warning is produced by the definition of the ArrayBuilder.addToList method:编译时,ArrayBuilder.addToList方法的定义会产生以下警告:
warning: [varargs] Possible heap pollution from parameterized vararg type T
When the compiler encounters a varargs method, it translates the varargs formal parameter into an array. 当编译器遇到varargs方法时,它将varargs形式参数转换为数组。However, the Java programming language does not permit the creation of arrays of parameterized types. 但是,Java编程语言不允许创建参数化类型的数组。In the method 在ArrayBuilder.addToList
, the compiler translates the varargs formal parameter T... elements
to the formal parameter T[] elements
, an array. ArrayBuilder.addToList
方法中,编译器将varargs形式参数T... elements
翻译到形式参数T[] elements
,数组。However, because of type erasure, the compiler converts the varargs formal parameter to 但是,由于类型擦除,编译器将varargs形式参数转换为Object[] elements
. Object[] elements
。Consequently, there is a possibility of heap pollution.因此,存在堆污染的可能性。
The following statement assigns the varargs formal parameter 以下语句将varargs形式参数l
to the Object
array objectArgs
:l
分配给Object
数组objectArgs
:
Object[] objectArray = l;
This statement can potentially introduce heap pollution. 此语句可能会导致堆污染。A value that does match the parameterized type of the varargs formal parameter 可以将与varargs形式参数l
can be assigned to the variable objectArray
, and thus can be assigned to l
. l
的参数化类型匹配的值分配给变量objectArray
,从而可以分配给l
。However, the compiler does not generate an unchecked warning at this statement. 但是,编译器不会在此语句中生成未检查的警告。The compiler has already generated a warning when it translated the varargs formal parameter 编译器在将varargs形式参数List<String>... l
to the formal parameter List[] l
. List<String>... l
翻译到形式参数List[] l
时已生成警告。This statement is valid; the variable 本声明有效;变量l
has the type List[]
, which is a subtype of Object[]
.l
具有类型List[]
,它是Object[]
的子类型。
Consequently, the compiler does not issue a warning or error if you assign a 因此,如果将任何类型的List
object of any type to any array component of the objectArray
array as shown by this statement:List
对象分配给objectArray
数组的任何数组组件,则编译器不会发出警告或错误,如下语句所示:
objectArray[0] = Arrays.asList(42);
This statement assigns to the first array component of the 此语句将包含一个objectArray
array with a List
object that contains one object of type Integer
.Ingeter
对象的List
对象分配给objectArray
数组的第一个数组组件。
Suppose you invoke 假设使用以下语句调用ArrayBuilder.faultyMethod
with the following statement:ArrayBuilder.faultyMethod
:
ArrayBuilder.faultyMethod(Arrays.asList("Hello!"), Arrays.asList("World!"));
At runtime, the JVM throws a 在运行时,JVM在以下语句中抛出ClassCastException
at the following statement:ClassCastException
:
// ClassCastException thrown here String s = l[0].get(0);
The object stored in the first array component of the variable 存储在变量l
has the type List<Integer>
, but this statement is expecting an object of type List<String>
.l
的第一个数组组件中的对象具有类型List<Integer>
,但此语句需要类型为List<String>
的对象。
If you declare a varargs method that has parameters of a parameterized type, and you ensure that the body of the method does not throw a 如果您声明的varargs方法具有参数化类型的参数,并且您确保该方法的主体不会由于varargs形式参数的不当处理而引发ClassCastException
or other similar exception due to improper handling of the varargs formal parameter, you can prevent the warning that the compiler generates for these kinds of varargs methods by adding the following annotation to static and non-constructor method declarations:ClassCastException
或其他类似异常,通过向静态和非构造函数方法声明添加以下注释,可以防止编译器为这些类型的varargs方法生成警告:
@SafeVarargs
The @SafeVarargs
annotation is a documented part of the method's contract; this annotation asserts that the implementation of the method will not improperly handle the varargs formal parameter.@SafeVarargs
注释是该方法合同的文件化部分;此注释断言该方法的实现不会不正确地处理varargs形式参数。
It is also possible, though less desirable, to suppress such warnings by adding the following to the method declaration:通过在方法声明中添加以下内容,也可以抑制此类警告(尽管不太理想):
@SuppressWarnings({"unchecked", "varargs"})
However, this approach does not suppress warnings generated from the method's call site. 但是,此方法不会抑制从方法的调用站点生成的警告。If you are unfamiliar with the 如果您不熟悉@SuppressWarnings
syntax, see Annotations.@SuppressWarnings
语法,请参阅注释。