java遗珠之泛型不可靠类型

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/lastsweetop/article/details/83028766

不可靠类型

可靠类型是在运行时包含所有完整信息的类型,包括原始类型,非泛型类型,原生类型和无边界通配符的调用。

不可靠类型是编译时类型擦除移除了一些信息,比如不是无边界通配符的其他情况。一个不可靠类型在运行时没有完整可用的信息,

参数化的变量引用不是该参数化类型的时候就会产生堆污染,如果程序执行某些操作,编译器给出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
来防止放弹出警告。

原文 

https://blog.csdn.net/lastsweetop/article/details/83028766

本站部分文章源于互联网,本着传播知识、有益学习和研究的目的进行的转载,为网友免费提供。如有著作权人或出版方提出异议,本站将立即删除。如果您对文章转载有任何疑问请告之我们,以便我们及时纠正。

PS:推荐一个微信公众号: askHarries 或者qq群:474807195,里面会分享一些资深架构师录制的视频录像:有Spring,MyBatis,Netty源码分析,高并发、高性能、分布式、微服务架构的原理,JVM性能优化这些成为架构师必备的知识体系。还能领取免费的学习资源,目前受益良多

转载请注明原文出处:Harries Blog™ » java遗珠之泛型不可靠类型

赞 (0)
分享到:更多 ()

评论 0

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址