是为了保持与旧(非通用)版本的
Collection
的向后兼容性吗?还是我遗漏了更微妙的细节?我看到这种模式也在 remove
中重复出现 (remove(Object o)
),但 add
被泛化为 add(E e)
。
contains()
采用 Object
,因为它匹配的对象不必与您传递给 contains()
的对象具有相同的类型;它只要求它们是平等的。根据 contains()
的规范,如果存在一个对象 contains(o)
使得 e
为 true,则 (o==null ? e==null : o.equals(e))
返回 true。请注意,没有任何要求 o
和 e
必须是同一类型。这是因为 equals()
方法接受 Object
作为参数,而不仅仅是与对象相同的类型。
虽然许多类都定义了
equals()
,因此其对象只能等于其自己类的对象,但情况并非总是如此。例如, List.equals()
的规范规定,如果两个 List
对象都是 List
并且具有相同的内容,则它们相等,即使它们是 List 的不同实现。因此,回到这个问题中的示例,可能有一个 Collection<ArrayList>
,并且我可以使用 contains()
作为参数来调用 LinkedList
,并且如果存在具有相同内容的列表,它可能会返回 true。如果 contains()
是通用的并将其参数类型限制为 E
,则这是不可能的。
事实上,
contains()
将任何对象作为参数,这使得您可以使用它来测试集合中是否存在满足特定属性的对象:
Collection<Integer> integers;
boolean oddNumberExists = integers.contains(new Object() {
public boolean equals(Object e) {
Integer i = (Integer)e;
if (i % 2 != 0) return true;
else return false;
}
});
在此回复。
为什么 Java 集合的删除方法不是通用的?
简而言之,他们希望最大化向后兼容性,因为集合早在泛型之前就已被引入。
我补充一下:他提到的视频值得一看。
http://www.youtube.com/watch?v=wDN_EYUvUq0
更新
澄清一下,(在视频中)说这句话的人是更新 java 地图和集合以使用泛型的人之一。如果他不知道,那是谁呢?
这是因为
contains
函数利用了 equals
函数,并且 equals
函数是在 Object 基类中定义的,其签名为 equals(Object o)
而不是 equals(E e)
(因为并非所有类都是通用的)。与 remove
函数的情况相同 - 它使用接受 Object 参数的 equals
函数遍历集合。
但这并不能直接解释这个决定,因为他们仍然可以使用类型 E 并允许它在调用
equals
时自动转换为 Object 类型;但我想他们希望允许在其他对象类型上调用该函数。使用 Collection<Foo> c;
然后调用 c.contains(somethingOfTypeBar)
并没有什么问题 - 它总是返回 false,因此不需要强制转换为 Foo 类型(这可能会引发异常),或者为了防止异常,使用typeof
打电话。因此,您可以想象,如果您要迭代具有混合类型的内容并在每个元素上调用 contains
,您可以简单地对所有元素使用 contains 函数,而不需要防护。
当你这样看时,它实际上让人想起“较新的”松散类型语言......
因为否则它只能与参数类型的精确匹配进行比较,特别是通配符集合将停止工作,例如
class Base
{
}
class Derived
extends Base
{
}
Collection< ? extends Base > c = ...;
Derived d = ...;
Base base_ref = d;
c.contains( d ); // Would have produced compile error
c.contains( base_ref ); // Would have produced compile error
编辑
对于认为这不是原因之一的怀疑者,这里是一个修改后的数组列表,其中包含一个将被泛化的 contains 方法
class MyCollection< E > extends ArrayList< E >
{
public boolean myContains( E e )
{
return false;
}
}
MyCollecttion< ? extends Base > c2 = ...;
c2.myContains( d ); // does not compile
c2.myContains( base_ref ); // does not compile
基本上
contains( Object o )
是一种让这个非常常见的用例与 Java 泛型一起使用的 hack。
“那篮子苹果里有这个橙子吗?”
显然无法给出正确的答案。但这仍然留下了太多的可能性:
集合API选择了第一个。但第二个选择也很有意义。这样的问题99.99%都是废话,所以别问!
Java 集合泛型类做出了合理的假设,即任何采用
contains()
方法需要被视为不可变方法,并且它的调用应该在泛型方法的实现中成为可能。这就是为什么 contains()
方法接受 Object
作为输入,而不是键入