Documentation

The Java™ Tutorials
Hide TOC
Non-Reifiable Types不可偿还类型
Trail: Learning the Java Language
Lesson: Generics (Updated)
Section: Type Erasure

Non-Reifiable Types不可偿还类型

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:本页涵盖以下主题:

Non-Reifiable Types不可偿还类型

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堆污染

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.如果确保代码在编译时没有警告,则不会发生堆污染。

Potential Vulnerabilities of Varargs Methods with Non-Reifiable Formal Parameters具有不可恢复形式参数的Varargs方法的潜在漏洞

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 Object[] elements. 但是,由于类型擦除,编译器将varargs形式参数转换为Object[] elementsConsequently, there is a possibility of heap pollution.因此,存在堆污染的可能性。

The following statement assigns the varargs formal parameter l to the Object array objectArgs:以下语句将varargs形式参数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 l can be assigned to the variable objectArray, and thus can be assigned to l. 可以将与varargs形式参数l的参数化类型匹配的值分配给变量objectArray,从而可以分配给lHowever, 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 List<String>... l to the formal parameter List[] l. 编译器在将varargs形式参数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 ClassCastException at the following statement:在运行时,JVM在以下语句中抛出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>的对象。

Prevent Warnings from Varargs Methods with Non-Reifiable Formal Parameters防止带有不可恢复形式参数的Varargs方法发出警告

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 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:如果您声明的varargs方法具有参数化类型的参数,并且您确保该方法的主体不会由于varargs形式参数的不当处理而引发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语法,请参阅注释


Previous page: Effects of Type Erasure and Bridge Methods
Next page: Restrictions on Generics