为什么Java Collections没有删除泛型方法?

问题

为什么不是Collection.remove(Object o)generic?

好像Collection<E>可以有boolean remove(E o);

然后,当你意外地尝试从aCollection<String>删除(例如)Set<String>而不是每个单独的字符串时,这将是编译时错误而不是稍后的调试问题。


#1 热门回答(70 赞)

remove()(inMap以及inCollection)不是通用的,因为你应该能够将任何类型的对象传递到remove()。删除的对象不必与传入toremove()的对象的类型相同;它只要求它们是平等的。从remove(),remove(o)的规范中删除了对象e,即(o==null ? e==null : o.equals(e))istrue。请注意,没有任何要求oe属于同一类型。这是因为236363271方法接受了一个Objectas参数,而不仅仅是与对象相同的类型。

虽然,通常情况下,很多类都有equals()定义,因此它的对象只能等于它自己的类的对象,但情况肯定并非总是如此。例如,List.equals()的规范表明,如果两个List对象都是Lists并具有相同的内容,则它们是相等的,即使它们是List的不同实现。所以回到这个问题的例子,有可能有一个aMap<ArrayList, Something>,并且我可以用aLinkedListas参数调用remove(),它应该删除具有相同内容的列表的键。如果remove()是通用的并且限制其参数类型,则这是不可能的。


#2 热门回答(64 赞)

Josh Bloch和Bill Pugh在Java Puzzlers IV:幽灵参考威胁,克隆攻击和转变复仇中提到了这个问题。

Josh Bloch说(6:41)他们试图生成Map的get方法,删除方法和其他一些方法,但"它根本不起作用"。

如果只允许集合的泛型类型作为参数类型,则有太多合理的程序无法生成。他给出的例子是aListofNumbers和aListofLongs的交集。


#3 热门回答(11 赞)

因为如果你的类型参数是通配符,则不能使用通用的删除方法。

我好像记得用Map的get(Object)方法来讨论这个问题。在这种情况下,get方法不是通用的,尽管它应该合理地期望传递与第一个类型参数相同类型的对象。我意识到,如果你使用通配符作为第一个类型参数传递Maps,那么如果该参数是通用的,则无法使用该方法从Map中获取元素。通配符参数不能真正满足,因为编译器无法保证类型是正确的。我推测add的一般原因是你需要在将它添加到集合之前保证类型是正确的。但是,在删除对象时,如果类型不正确,则无论如何都不会匹配任何内容。如果参数是通配符,那么该方法将无法使用,即使你可能有一个GUARANTEE属于该集合的对象,因为你只是在前一行中有对它的引用....

我可能没有很好地解释它,但它对我来说似乎合乎逻辑。