The Java™ Tutorials — Generics :Non-Reifiable Types 不可具体化类型

The Java™ Tutorials — Generics :Non-Reifiable Types 不可具体化类型

原文地址:https://docs.oracle.com/javase/tutorial/java/generics/nonReifiableVarargsType.html

关键点

  • 可具体化类型和不可具体化类型的定义: 
    • 可具体化类型:就是一个可在整个运行时可知其类型信息的类型。 
      • 包括:基本类型、非泛型类型、原始类型和调用的非受限通配符。
    • 不可具体化类型:无法整个运行时可知其类型信息的类型,其类型信息已在编译时被擦除: 
      • 例如:List<String>List<Number>,JVM无法在运行时分辨这两者
  • 堆污染: 
    • 发生时机:当一个参数化类型变量引用了一个对象,而这个对象并非此变量的参数化类型时,堆污染就会发生。
    • 分模块对代码进行分别编译,那就很难检测出潜在的堆污染,应该同时编译
  • 带泛型的可变参数问题: 
    • T...将会被翻译为T[],根据类型擦除,进一步会被处理为Object[],这样就可能造成潜在的堆污染
  • 避免堆污染警告 
    • @SafeVarargs:当你确定操作不会带来堆污染时,使用此注释关闭警告
    • @SuppressWarnings({"unchecked", "varargs"}):强制关闭警告弹出(不建议这么做)

全文翻译

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. 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
  • Heap Pollution
  • Potential Vulnerabilities of Varargs Methods with Non-Reifiable Formal Parameters
  • Preventing Warnings from Varargs Methods with Non-Reifiable Formal Parameters

本章节将讨论如下话题:

  • 不可具体化类型
  • 堆污染
  • 具有不可具体化形参的可变参数方法的潜在隐患
  • 避免来自不可具体化形参的可变参数方法的警告

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 areList<String> and List<Number>; the JVM cannot tell the difference between these types at runtime. 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.

不可具体化类型是指其类型信息在编译时被类型擦除机制所移除的类型。这里的类型移除是指在调用没有定义为无限制通配符的泛型时所进行的类型擦除。我们无法在运行时可知一个不可具体化类型的所有信息。一个此类型的例子就是List<String>List<Number>。JVM在运行时无法分辨两者。正如《泛型的约束》中讲到的那样,有几种特定情景下是不能使用泛型的:例如在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 具有不可具体化形参的可变参数方法的潜在隐患

Generic methods that include vararg input parameters can cause heap pollution.

具有可变输入参数的泛型方法可以引起堆污染。

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:

下面的例子HeapPollutionExample使用了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. However, the Java programming language does not permit the creation of arrays of parameterized types. In the method ArrayBuilder.addToList, the compiler translates the varargs formal parameter T… elements to the formal parameter T[] elements, an array. However, because of type erasure, the compiler converts the varargs formal parameter to Object[] elements. Consequently, there is a possibility of heap pollution.

当编译遇到可变参数方法时,它就会将可变参数翻译成一个数组。然而,Java禁止参数化类型的数组。在方法ArrayBuilder.addList中,编译器将可变形参T…的元素翻译成为形参T[]的元素。然而,由于类型擦除,编译器又将可变形参转化为Object[]的元素,这就进而导致了一个可能的堆污染。

The following statement assigns the varargs formal parameter 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 l can be assigned to the variable objectArray, and thus can be assigned to 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 List<String>...lto the formal parameter List[] l. This statement is valid; the variable l has the type List[], which is a subtype of Object[].

这个语句会引起潜在堆污染。与可变形参l的参数化类型并不匹配的值可以赋值给objectArray,因此也就能赋值给l。然而,编译器并不在此句上生成未检查警告。在将可变形参List<String> l翻译成形参List[] l时,编译就已经生成了一个警告。此句是有效的;变量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.

这个语句将objectArray的第一个元素赋值为一个List对象,这个List持有一个Integer元素。

Suppose you invoke ArrayBuilder.faultyMethod with the following statement:

假设你通过下面的语句去调用ArrayBuilder.faultyMetho方法时:

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 typeList<String>.

l数组中的第一个元素存储了一个List<Integer>类型的对象,但是此句期望的类型却是List<String>

Prevent Warnings from Varargs Methods with Non-Reifiable Formal Parameters 避免来自不可具体化形参的可变参数方法的警告

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:

如果你定义了一个具有参数化类型参数的可变参数方法,并且你确保方法不会抛出一个ClassCastException异常,或者其他因处理可变形参不当而引起的相似异常时,你就可以人为地屏蔽编译器生成的这些警告。为此,你需要为静态和非构造器方法声明中加入下面的注释:

@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注释是方法概要的一部分;这个注释断言此方法的实现会恰当的处理可变形参。

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.

然而,这种手段并不会阻止在方法调用的地方产生警告。如果你对@SuppressWarning语法还不熟,请参阅《Annotations(注释)》章节。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值