当eclipse建议我的代码应该是那样的时候,我得到一个ClassCastException。
我有一个名为Kort的课程。
ArrayList<Kort> kort = new ArrayList<Kort>();
然后我使用toArray()
,而eclipse建议它应该是这样的:Kort[] array = (Kort[])kort.toArray()
;
但是它给了我这个异常:ClassCastException! :(
答案 0 :(得分:3)
我的建议是:
kort.toArray(new Kort[0])
从技术上讲,这可能比给出正确的尺寸要慢一些。但是,您不需要两次提及集合变量名称,因此产生错误的可能性更小。它也更容易阅读。作为奖励,它也适用于并发集合,其中调用size
并没有真正有意义。
但是,最好的方法是尽可能避免使用引用数组。
答案 1 :(得分:2)
使用
kort.toArray(new Kort[kort.size()]);
答案 2 :(得分:2)
你能做的是:
Kort[] array = kort.toArray(new Kort[kort.size()]);
这被认为是更好的,因为它保持阵列上的类型安全。如果你不关心/想要那个,那么就忽略这个建议。不带参数的toArray()方法返回一个Object []数组。
答案 3 :(得分:2)
问题的根源是Object[] toArray()
API中Object[] toArray(Object[])
和java.util.Collection
方法之间的差异。
第一个表单分配一个正确大小的数组来保存集合的成员,然后将成员引用分配给数组。由于集合类不知道成员的实际类型(请参阅下面的注释),因此API指定结果是Object[]
的实例;即好像是使用new Object[size]
分配的。
第二种形式将数组作为参数(通常)存储集合成员引用的位置。因此,程序通过传递所需类型的数组来确定结果的类型。如果提供的数组足以容纳集合元素,toArray
方法将返回提供的数组实例。如果不是,则为新数组分配与提供的数组实例相同的类型。 (这可以使用Array.newInstance(clazz, size)
反射性地完成,其中clazz
是提供的数组的组件类。请注意,类型参数不用于执行此操作...并且不能使用它。)
所以正在发生的事情是Eclipse不够聪明,不知道对你的错误的真正纠正是使用不同的方法重载。为了进行这种修正,需要“知道”toArray
方法的两种形式的特定语义。这是一个很高的订单IMO。
经验教训是,Eclipse的建议更正是Just Suggestions ...并且不能保证是正确的修复。
注意:由于类型擦除,集合类不知道要在toArray()
情况下创建的相应数组类。有关如何实例化类型的信息对于实现toArray
的类不可用。但考虑到通常可以插入Collection<T>
不是T
的东西(通过忽略“不安全的输入”编译器警告),它可能是好东西结果类型是Object[]
!
此问题早于泛型类型;自从Java 1.2中引入集合框架以来,已经存在这种方法的两种形式。
编辑:在评论中@Thilo建议如果Java从一开始就支持泛型,就不会出现这个问题。我对此的回答是它并没有那样发生,我们不能说如果有的话会发生什么。但我们可以说使用Java泛型,因为它们当前已定义,如果不重新设计集合API,就不可能做到这一点。具体来说,泛型类无法弄清楚实际类型已被用作给定实例的类型参数。没有这些信息,它无法知道要实例化的正确数组类型。实际上,如果您希望泛型类型创建类型参数或某些相关类型的实例,则必须设计API,以便相关方法具有对实际参数类型的Class
对象的运行时访问权限。例如,实际的Class对象可以作为构造函数参数提供。
答案 4 :(得分:0)
的另一个优点
kort.toArray(new Kort[kort.size()]);
在
(Kort[])kort.toArray();
如果您的kort集合为空,则生成的to数组应为对象类型的零长度数组,如果将该类型转换为Kort,则会抛出异常。
使用kort.toArray(new Kort[kort.size()]);
可确保即使集合为空,返回的数组仍然是所需的类型。