Java中为什么不允许直接创建泛型数组

在Java中,如果创建泛型数组,会出现以下编译错误, 例如
List<String>[] stringLists = new List<String>[10];
会提示
Error:(9, 38) java: 创建泛型数组
但是却可以创建泛型数组的引用
List<String>[] stringLists = null;
并将一个普通数组的引用赋值给它。
List<String>[] stringLists = new List[10];

package test;

import java.util.ArrayList;
import java.util.List;

public class Main {
    public static void main(String[] args) {
        List<String>[] stringLists = new List[10];
        stringLists[0] = new ArrayList<>();
        stringLists[0].add("HelloWorld");
    }
}

Java中为什么不允许直接创建泛型数组?
《Effective Java》第五章给出了一个解释:

使用泛型的作用是使得程序在编译期可以检查出与类型相关的错误,但是如果使用了泛型数组,这种能力就会受到破坏。

假如我们可以声明这样一个泛型数组(实际上是不可以的):
List<String>[] stringLists = new List<String>[10];
由于在 Java 中,数组是协变(covariant)的,这意味着基类类型的数组可以接收子类类型的数组,例如:
Object[] objects = stringLists;
一旦我们这样做之后,就可以通过objects向 stringLists中添加非List<String>类型的数据。

List<Integer> intList = Arrays.asList(1);
objects[0] = intList;

随后,再使用 stringList 时,stringList[0] 就会保存 intList, 而使用下面的代码,编译器不会提示错误,但运行时,就会出错。
String str = stringList[0].get(0);

即使创建出来“泛型数组”以上错误也依然存在。

List<String>[] stringLists = (List<String>[])new List[10];
Object[] objects = stringLists;
List<Integer> intList = Arrays.asList(1);
objects[0] = intList;
String str = stringLists[0].get(0); //runtime error

当我们创建泛型容器时:

public class Array<E> {
    private E elem[];
    private static final int INITIAL_ARRAY_LENGTH = 100;

    public Array() {
        elem = new E[INITIAL_ARRAY_LENGTH]; //编译期就会报错:不能创建泛型数组
    }
}

解决办法:

class Array<E> {
    private E elem[];
    private int size;

    @SuppressWarnings("unchecked")
    public Array(Class<?> type, int size) {
        elem = (E[]) java.lang.reflect.Array.newInstance(type, size);
    }

    public void add(E e) {
        elem[size++] = e;
    }

    public E get(int i) {
        return elem[i];
    }
}

或者:

class Array<E> {
    private E elem[];
    private int size;

    @SuppressWarnings("unchecked")
    public Array(int size) {
        elem = (E[]) new Object[size];//强制类型转换就是为了逃避编译时的检查
    }

    public void add(E e) {
        elem[size++] = e;
    }

    public E get(int i) {
        return elem[i];
    }

    @Override
    public String toString() {
        return "Array{" +
                "elem=" + Arrays.toString(elem) +
                ", size=" + size +
                '}';
    }
}

泛型的出现在很大程度上是为了避免运行时出现烦人的 ClassCastException,可是具有讽刺意味的是,泛型数组却又导致了
ClassCastException异常的出现。

参考:
http://minixbeta.github.io/%E6%8A%80%E6%9C%AF/2014/09/18/why-java-no-generic-array.html
https://www.zhihu.com/question/20928981/answer/117521433
http://www.blogjava.net/deepnighttwo/articles/298426.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

N3verL4nd

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值