为什么不能用Java实现泛型数组?

Nec*_*ann 3 java arrays generics

Java使用类型擦除

我的理解new ArrayList<String>()是将其转换为原始类型,并且使用大量的语法糖来假装Object的这个ArrayList就像String的ArrayList.Java将此称为类型擦除.

例如

这是我用Java写的:

public static void main(String[] args) {
    ArrayList<String> stringList = new ArrayList<>();
    stringList.add("foo");
    String s = stringList.get(0);
}
Run Code Online (Sandbox Code Playgroud)

当我反编译字节码时,我得到了这个:

public static void main(String[] args) {
    ArrayList<String> stringList = new ArrayList();
    stringList.add("foo");
    String s = (String)stringList.get(0);
} 
Run Code Online (Sandbox Code Playgroud)

因此

为什么无法使用编译器为类型擦除提取的"shtick" 自动new T[]转换为(T[]) new Object[] 自动转换?

请不要将我引用到这个问题:我无法在Java中创建通用数组类型的原因是什么?特别是这个评论:

问题比答案更深刻,因此需要进一步调查.如你所说的类型信息被删除,在编译代码中我们没有两个泛型类型之间的区别 - 我们只有基类型 - 所以为什么T[]- 编译到Object[].在这种情况下,一切都会很好 - 数组将记住它是使用对象类型创建的,并将保存所有类型.然而,对我来说,真正的问题是数组是协变的意味着Animal[]可以分配给Object[].另一方面,泛型不是ArrayList<Animal> 不能分配的ArrayList<Object>

因为这个逻辑是有缺陷的!

这里有两个进程.

  1. 编译器强制执行"人为"不变性ArrayList<String>.

  2. 编译器转换ObjectT.

同样,为什么不能使用形成所有泛型的简单语法糖在Java中实现泛型数组,同时保持数组的正常协方差?

shm*_*sel 8

可以通过两种方式强制执行类型安全:在运行时或编译时.

数组在运行时强制执行:

Object[] array = new Integer[1];
array[0] = "";
// ArrayStoreException!
Run Code Online (Sandbox Code Playgroud)

泛型在编译时强制执行:

List<Object> list1 = new ArrayList<Integer>();
// does not compile!

List<? extends Object> list2 = new ArrayList<Integer>();
list2.add(1);
// does not compile!
Run Code Online (Sandbox Code Playgroud)

因为它T[]是一个数组,所以它必须是协变的,但是由于类型擦除,在运行时没有办法检查类型,如下例所示:

Object[] array = (T[])new Object[1];
array[0] = 1;
Run Code Online (Sandbox Code Playgroud)

由于在运行时array实际上类型Object[],因此无论发生什么T情况,此代码都将编译并运行而不会出现错误.这会导致堆污染,这通常会导致您的代码在某个不可预测的地方或时间失败,从而难以诊断和修复.因此警告.