问题
为什么不是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
。请注意,没有任何要求o
和e
属于同一类型。这是因为236363271方法接受了一个Object
as参数,而不仅仅是与对象相同的类型。
虽然,通常情况下,很多类都有equals()
定义,因此它的对象只能等于它自己的类的对象,但情况肯定并非总是如此。例如,List.equals()
的规范表明,如果两个List对象都是Lists并具有相同的内容,则它们是相等的,即使它们是List
的不同实现。所以回到这个问题的例子,有可能有一个aMap<ArrayList, Something>
,并且我可以用aLinkedList
as参数调用remove()
,它应该删除具有相同内容的列表的键。如果remove()
是通用的并且限制其参数类型,则这是不可能的。
#2 热门回答(64 赞)
Josh Bloch和Bill Pugh在Java Puzzlers IV:幽灵参考威胁,克隆攻击和转变复仇中提到了这个问题。
Josh Bloch说(6:41)他们试图生成Map的get方法,删除方法和其他一些方法,但"它根本不起作用"。
如果只允许集合的泛型类型作为参数类型,则有太多合理的程序无法生成。他给出的例子是aList
ofNumber
s和aList
ofLong
s的交集。
#3 热门回答(11 赞)
因为如果你的类型参数是通配符,则不能使用通用的删除方法。
我好像记得用Map的get(Object)方法来讨论这个问题。在这种情况下,get方法不是通用的,尽管它应该合理地期望传递与第一个类型参数相同类型的对象。我意识到,如果你使用通配符作为第一个类型参数传递Maps,那么如果该参数是通用的,则无法使用该方法从Map中获取元素。通配符参数不能真正满足,因为编译器无法保证类型是正确的。我推测add的一般原因是你需要在将它添加到集合之前保证类型是正确的。但是,在删除对象时,如果类型不正确,则无论如何都不会匹配任何内容。如果参数是通配符,那么该方法将无法使用,即使你可能有一个GUARANTEE属于该集合的对象,因为你只是在前一行中有对它的引用....
我可能没有很好地解释它,但它对我来说似乎合乎逻辑。