在此处回答相关问题时: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 bothX<Y>
andX<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/