Java 为什么不支持泛型数组

缘由

之前leetcode刷题的时候,某道题试图新建一个HashMap的数组,总是编译出错,然后突然反应过来,Java里是不能按照像通常新建基本类型的数组一样,直接新建泛型数组的。希望我能以比较简单明了的方式说明其中的原因。

分析

首先对于Java数组,数组必须明确知道内部元素的类型,而且编译器会”记住“这个类型,每次往数组里插入新元素都会进行类型检查,不匹配会抛出java.lang.ArrayStoreException错误。

如果试图创建一个泛型数组,直接写成下面这样的话:

HashMap<Integer> map = new HashMap<Integer>[];

其实是无法编译通过的。
原因就是Java的泛型是通过类型擦除(type erasure)来实现的。什么是类型擦除呢,简单来说Java在编译期间,所有的泛型信息都会被擦除掉。

如在代码中定义的List<object>List<String>等类型,在编译后都会变成List

List<String> strList = new ArrayList<String>(); 
List<Object> objList = new ArrayList<Object>();
List rawList = new ArrayList();

比如上面3个List,擦除类型参数以后,List中的实际元素都是Object。JVM看到的只是List,而由泛型附加的类型信息对JVM来说是不可见的。

Java编译器会在编译时尽可能的发现可能出错的地方,但是仍然无法避免在运行时刻出现类型转换异常的情况。所以由于类型擦除的原因,Java是禁止直接创建泛型数组实例的。

泛型数组

如何创建真正的泛型数组呢?我们不能直接创建,但可以把数组强制转换成泛型类型。比如:

List<Integer>[] genericArray = (List<Integer>[])new ArrayList[10];

这样编译的时候并不会报错,因为Java虽然禁止直接创建泛型数组实例,但并没有禁止声明一个泛型数组引用。所以仍然可以通过强制转型原生类型数组的方式,绕过限制。

虽然编译期不会报错,但是这样做仍然有潜在的风险,因为类型擦除的存在,遇到下面这种情况运行期间就挂了:

List<Integer>[] genericArray = (List<Integer>[])new ArrayList[10];
genericArray[0] = new ArrayList<String>(Arrays.asList(new String[]{"Hello"}));

总结

Java 中不允许直接创建泛型数组,所以并不建议通过各种方式绕过编译器的限制,这样会带来在代码出错时,编译器也有可能无法及时发现错误,从而带来潜在的风险。

想要用泛型数组的时候,还是老老实实用ArrayList吧!。

参考文章:
[[1]]java为什么不支持泛型数组? - 胖胖的回答 - 知乎
[[2]]Java 泛型总结(二):泛型与数组

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  •   在Effective中讲到泛型之处提到了一个概念,类型擦除器,这是什么呢?接下来我们跟随这篇文章探索类型擦除的...
    凌云_00阅读 2,173评论 0 8
  • 开发人员在使用泛型的时候,很容易根据自己的直觉而犯一些错误。比如一个方法如果接收List作为形式参数,那么如果尝试...
    时待吾阅读 1,077评论 0 3
  • 转载: https://blog.csdn.net/s10461/article/details/53941091...
    DaneYang阅读 500评论 1 6
  • 我努力去拼凑着 这些年 我们的记忆 却零散的捡拾不起 指尖的触痛 划向心底 刺伤着无法呼吸 最初的错误似乎开始了被...
    柚宝妈咪阅读 245评论 0 11
  • 本书用生动、形象的语言,以漫画、故事的方式,全面揭示了区块链的基本原理、应用及发展前景,告诉读者区块链是什么,区块...
    张聪_2048阅读 27,736评论 0 1