为什么我们有包含(Object o)而不是contains(E e)?

时间:2010-06-08 00:43:44

标签: java generics collections contains

是否要保持与Collection的较旧(非通用化)版本的向后兼容性?还是有一个我错过的更细微的细节?我也在removeremove(Object o))中重复了这种模式,但add被归为add(E e)

5 个答案:

答案 0 :(得分:11)

contains()需要Object,因为它匹配的对象不必与传递给contains()的对象的类型相同;它只要求它们是平等的。根据{{​​1}}的规范,如果存在contains()对象contains(o),则e返回true。请注意,没有任何内容要求(o==null ? e==null : o.equals(e))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;
    }
});

答案 1 :(得分:5)

这里回答。
Why aren't Java Collections remove methods generic?
简而言之,他们希望最大限度地提高向后兼容性,因为收藏品早在仿制药之前就已经推出了。

从我这里补充一下:他所指的视频值得一看 http://www.youtube.com/watch?v=wDN_EYUvUq0

<强>更新
为了澄清,那个说(在视频中)是更新java地图和集合以使用泛型的人之一。如果他不知道,那么谁。

答案 2 :(得分:4)

这是因为contains函数使用equals函数,equals函数在基础Object类中定义,签名为equals(Object o)而不是{{ 1}}(因为并非所有类都是通用的)。与equals(E e)函数相同的情况 - 它使用带有Object参数的remove函数遍历集合。

然而,这并没有直接解释决定,因为他们仍然可以使用类型E并允许它在调用equals时自动转换为对象类型;但我想他们想要允许在其他Object类型上调用该函数。拥有equals然后调用Collection<Foo> c;没有任何问题 - 它总是返回false,因此它不需要强制转换类型Foo(可以抛出异常),或者保护例外,c.contains(somethingOfTypeBar)电话。所以你可以想象如果你在使用混合类型迭代并在每个元素上调用typeof,你可以简单地在所有元素上使用contains函数而不需要守卫。

当你以这种方式看待它时,它实际上让人想起“更新”的松散型语言......

答案 3 :(得分:0)

因为否则它只能与参数类型的完全匹配进行比较,特别是通配符集合将停止工作,例如。

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

修改
对于那些认为不是其中一个原因的怀疑者,这里是一个修改后的数组列表,其中包含一个包含方法

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 Generics一起使用的黑客。

答案 4 :(得分:0)

“那篮子里的苹果含有这种橙子吗?”

显然无法给出正确答案。但这仍然有可能:

  1. 答案是假的。
  2. 问题形成不好,不应该通过编译。
  3. 收集api选择了第一个。但第二选择也很有意义。像这样的问题是99.99%的废话问题,所以甚至不要问!