java遗珠之泛型不可靠类型
Posted 吴冬冬
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java遗珠之泛型不可靠类型相关的知识,希望对你有一定的参考价值。
不可靠类型
可靠类型是在运行时包含所有完整信息的类型,包括原始类型,非泛型类型,原生类型和无边界通配符的调用。
不可靠类型是编译时类型擦除移除了一些信息,比如不是无边界通配符的其他情况。一个不可靠类型在运行时没有完整可用的信息,
堆污染
当参数化的变量引用不是该参数化类型的时候就会产生堆污染,如果程序执行某些操作,编译器给出unchecked警告时,就会发生这种情况。如果unchecked警告产生的时候,无论是编译时还是运行时,这个操作的正确性都无法保证。比如混淆了原生类型和参数化类型,或者执行了unchecked的强制转换。
在通常情况下,代码都是同时编译的,编译器会给出unchecked的警告,告诉你堆污染潜在的可能性。但如果代码是分别编译的,你就很难察觉到堆污染的潜在风险。如果你保证你的代码没有警告,你就能保证没有堆污染产生。
不可靠类型作为可变参数方法时的潜在缺陷
包含可变参数的泛型方法会引起堆污染,看下面的例子
public class ArrayBuilder
public static <T> void addToList(List<T> listArg, T... elements)
for (Object x : elements)
listArg.add((T) 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
调用类如下:
public class HeapPollutionExample
public static void main(String[] args)
List<String> stringListA = new ArrayList<>();
List<String> stringListB = new ArrayList<>();
ArrayBuilder.addToList(stringListA, "Seven", "Eight", "Nine");
ArrayBuilder.addToList(stringListB, "Ten", "Eleven", "Twelve");
List<List<String>> listOfStringLists =
new ArrayList<>();
ArrayBuilder.addToList(listOfStringLists,
stringListA, stringListB);
ArrayBuilder.faultyMethod(Arrays.asList("Hello!"), Arrays.asList("World!"));
当编译的时候ArrayBuilder.addToList
会给出警告
[unchecked] 对于类型为List<String>[]的 varargs 参数, 泛型数组创建未经过检查
当编译器遇到可变参数方法时,它会把可变参数转换为数组,而java语言并不会创建参数化类型的数组。在方法ArrayBuilder.addToList
中,编译器会将T...
转换成T[]
,但是由于类型擦除,编译器最终会转为Object[]
,因此就会出现堆栈污染。
接下来的语句将可变参数分配给Objcet
数组objectArgs
,
Object[] objectArray = l; // Valid
这条语句有潜在的堆污染,但是编译器却未给出unchecked的警告,因为编译器已经在把List<String>... l
转换成List[] l
的时候产生了警告,因此这条语句是有效的,因为List[]
是Object[]
的子类型。
因此你接下来给objectArray
分配任意类型的List对象时,编译器也不会产生警告或者错误,比如下面的语句:
objectArray[0] = Arrays.asList(42);
然后运行的时候就在下面的语句报异常ClassCastException
:
String s = l[0].get(0);
因为你赋值的是一个List<Integer>
.
取消不可靠类型作为可变参数方法时的警告
如果你定义了参数化类型的可变参数方法,并且代码中不会产生ClassCastException
异常,或者因为可变参数处理不当的其他异常,就可以使用注解@SafeVarargs
来防止放弹出警告。
以上是关于java遗珠之泛型不可靠类型的主要内容,如果未能解决你的问题,请参考以下文章