java - 为什么我们可以使用具有泛型引用的数组

标签 java generics jakarta-ee scjp

在此处回答相关问题时:https://stackoverflow.com/a/9872630/82609

我尝试执行以下操作:

Comparator<String>[] comparators = new Comparator[] {...};

有效!但以下不是:

Comparator<String>[] comparators = new Comparator<String>[] {...};

关于相关问题,我做了以下假设:

I guess it's because initially the array contract may be something like this:

If you create an array of type X, you will NEVER EVER be able to put anything in it that IS-NOT-AN X. If you try, you'll get an ArrayStoreException

因此允许创建具有泛型的数组会导致不同的结果 规则如下:

If you create an array of type X<Y>, you will NEVER EVER be able to put anything that IS-NOT-AN X. If you try, you'll get an ArrayStoreException. But you CAN add both X<Y> and X<Z> objects because of type erasure!


但想想看,如果有:

Comparator<String>[] comparators = new Comparator<String>[] {...};

我真的不明白为什么这是不可能的,因为使用这样的东西会:

  • 检查运行时插入的类
  • 检查编译时插入的类类型

我们终于可以使用具有泛型类型引用的数组,并且由于无法创建具有泛型类型的数组,我认为很多人甚至不知道这是可能的。

我只是想知道是否有人知道这个选择背后的原因?

这有点像强制人们使用List<String> = new ArrayList();而不是使用 List<String> = new ArrayList<String>();


dimitrisli 你从 Joshua Bloch 的名著中举了一个很好的例子。 正如您/他所解释的那样,同时使用泛型数组和协方差是危险的,并且可能导致 ClassCastException,而我们期望使用协方差的数组出现 ArrayStoreException。

但请注意以下内容仍然合法并导致相同的结果:

List<String>[] stringLists = new List[1];
List<Integer> intList = Arrays.asList(42);
Object[] objects = stringLists;
objects[0] = intList;
String s = stringLists[0].get(0);

但是,它会在编译时产生未经检查的转换警告,正如您提到的,在运行时会产生 ClassCastException。

最佳答案

我知道您的出发点(从实际意义上讲,我基本上同意),但我认为存在差异导致当前情况。

正如您提到的,删除意味着通用参数在运行时不可用,因此在编译时检查类型(对于 List<String> 或您的 Comparator<String>[] )。至关重要的是,这是基于变量的通用参数。

另一方面,数组在插入时会在运行时检查其参数的类型,因此它们可以抛出 ArrayStoreException。如果它们被滥用(通常是由于滥用它们的协方差)。因此,数组需要能够在内部执行两个要点检查,当然它们不能在运行时检查通用参数。因此,实例化一个泛型数组是没有意义的,因为该数组必须完全忽略泛型参数,这充其量会产生误导。

也就是说,将这样的数组分配给参数化的引用 确实有意义,因为那时编译器可以执行通用检查。您认为这涵盖了所有基础并确保检查了通用类型(只要变量参数化正确)是正确的。

这个选择背后的根本原因,以及为什么数组在这方面不同于集合,是数组在插入时需要实际检查其参数的类型,而集合只是相信你的话并允许类型错误冒泡到 ClassCastException稍后。

关于java - 为什么我们可以使用具有泛型引用的数组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9886417/

相关文章:

java - 组合与继承?

swift - 歧义类型推断

ios - 如何检测类型对于通用 propertyWrapper 是可选的

java - 如何在 JPA 中创建和处理复合主键

java - Apache Tomcat 应用程序中的相对文件路径引用

java - 无法在 Spring Security 中用自定义替换标准登录表单

java - 自定义 AppenderBase 未被调用

java - Spring Boot + Angular 5 - http.post 空值

c# - 这可能使用泛型吗? C#

java - 用drawstring()写入一个变量