Java通用数组:为什么要编译,这意味着什么?

Sar*_*123 4 java arrays generics

Java不允许直接创建通用数组。我知道由于擦除,泛型类型在运行时未知,而数组在运行时需要类型检查,因此两者是不兼容的。

这段代码无法编译-

Holder<Integer>[] integers = new Holder<Integer>[5];
Run Code Online (Sandbox Code Playgroud)

很好,但是我不确定为什么这段代码实际上会编译(警告不安全的类型转换)?

Holder<Integer>[] holders = new Holder[5];
holders[0] = new Holder<Integer>(5);
holders[1] = new Holder<Integer>(5);
holders[2] = new Holder<Integer>(5);
Run Code Online (Sandbox Code Playgroud)

我不完全了解我实际上是通过删除菱形括号来欺骗编译器的。创建通用数组是否可以接受?

此外,当我将此行添加到代码中时,holders[3] = new Holder<String>("Hello"); 它引发了编译错误,Holder<String> can not be converted to Holder<Integer> 我发现这很奇怪,因为据我所知,不允许泛型数组的整个想法是因为类型擦除会导致数组无法区分两种不同的泛型类型。但是在此示例中,编译器可以检测到错误的类型转换。

我在这里想念什么?

Swe*_*per 5

此页面上,您可以确切地了解为什么不允许创建泛型类型的数组:

Object[] stringLists = new List<String>[];  // compiler error, but pretend it's allowed
stringLists[0] = new ArrayList<String>();   // OK
stringLists[1] = new ArrayList<Integer>();  // An ArrayStoreException should be thrown,
                                            // but the runtime can't detect it.
Run Code Online (Sandbox Code Playgroud)

stringLists 应该只能存储List<String>,但是通过使用上面的代码,由于类型擦除,我不仅可以欺骗编译器,还可以欺骗运行时,从而允许我将a存储ArrayList<Integer>到中stringLists

但我不确定为什么这段代码实际上可以编译

好吧,因为Holder原始类型。请参阅什么是原始类型,为什么我们不应该使用它?。就编译器和运行时而言,完全可以创建原始类型的数组,因为在这里您并不是在说“该数组只能存储Holder<Integer>”,而是在说“该数组只能存储Holder(任何东西)。

创建通用数组是否可以接受?

嗯,您的阵列在技术上不是通用的。我可以将其分配给a Holder[]并将a 分配给Holder<Foo>其元素之一,并且不会发生异常或编译器错误。就编译器而言,这是“可以接受的”,但是由于您失去了类型安全性,因此不建议您使用它。您应该改用类似的方法ArrayList<Holder<Integer>>

我发现这很奇怪,因为据我所知,不允许通用数组的整个想法是因为由于类型擦除,数组无法区分两种不同的通用类型。但是在此示例中,编译器可以检测到错误的类型转换。

编译器无法检测到它,不是因为数组不允许您放入Holder<String>,而是因为变量的编译时类型是Holder<Integer>[]。编译器仍然可以通过查看编译时间类型来检查类型,但是一旦您丢失了编译时间类型(将其分配给type Object[]或变量Holder[]),它就无法为您完成操作。数组本身首先允许任何类型的Holder,因为它是一个Holder[]