代码之家  ›  专栏  ›  技术社区  ›  Vivin Paliath

为什么我们有contains(对象o)而不是contains(e)?

  •  17
  • Vivin Paliath  · 技术社区  · 14 年前

    它是否要与旧的(非通用的)版本保持向后兼容性? Collection ?还是有更微妙的细节让我错过了?我看到这个模式在 remove 也( remove(Object o) ) add 被遗传为 add(E e) .

    5 回复  |  直到 14 年前
        1
  •  11
  •   newacct    14 年前

    contains() 采取一个 Object 因为它匹配的对象不必与您传入的对象类型相同 容器() 它只要求它们是相等的。从规范 容器() , contains(o) 如果存在对象,则返回true e 这样 (o==null ? e==null : o.equals(e)) 是真的。请注意,没有任何要求 o e 相同类型。这是因为 equals() 方法接受 对象 作为参数,而不仅仅是与对象相同的类型。

    尽管许多类 等式() 定义它的对象只能等于它自己的类的对象,当然情况并非总是这样。例如,规范 List.equals() 说那两个 List 如果两个对象都是 和具有相同的内容,即使它们是列表的不同实现。所以回到这个问题的例子,有可能 Collection<ArrayList> 让我给你打电话 容器() 用一个 LinkedList 作为参数,如果有一个具有相同内容的列表,它可能返回true。如果 容器() 是泛型的,并将其参数类型限制为 E .

    事实上, 容器() 将任何对象作为参数允许有趣的使用,您可以使用它来测试集合中是否存在满足某个属性的对象:

    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;
        }
    });
    
        2
  •  5
  •   Community CDub    7 年前

    这里回答。
    Why aren't Java Collections remove methods generic?
    简言之,他们希望最大限度地提高向后兼容性,因为集合早在泛型之前就被引入了。

    我还想补充一点:他所指的视频值得一看。
    http://www.youtube.com/watch?v=wDN_EYUvUq0

    更新
    为了澄清这一点,在视频中说的人是更新Java地图和集合以使用泛型的人之一。如果他不知道,那是谁。

        3
  •  4
  •   Ricket    14 年前

    这是因为 contains 函数利用 equals 函数,以及 等于 函数在基对象类中定义,其签名为 equals(Object o) 而不是 equals(E e) (因为并非所有类都是泛型的)。同一个案例 remove 函数-它使用 等于 接受对象参数的函数。

    但是,这并不能直接解释该决定,因为它们可能仍然使用E类型,并允许在调用时自动将其强制转换为类型对象。 等于 但是我想他们希望允许在其他对象类型上调用函数。有了一个 Collection<Foo> c; 然后打电话 c.contains(somethingOfTypeBar) -它总是返回false,因此它不需要强制转换为foo类型(可以引发异常)或保护 typeof 打电话。因此,您可以想象,如果您正在迭代具有混合类型的内容并调用 包含 在每个元素上,您可以简单地在所有元素上使用包含函数,而不需要保护。

    它实际上让人联想到“更新的”松散类型的语言,当你这样看的时候…

        4
  •  0
  •   Alexander Pogrebnyak    14 年前

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

    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泛型一起工作。

        5
  •  0
  •   irreputable    14 年前

    “那篮苹果里有这个橘子吗?”

    显然不能给出一个真实的答案。但这仍然留下了太多的可能性:

    1. 答案是错误的。
    2. 这个问题格式不好,不应该通过编译。

    集合API选择了第一个。但第二个选择也会是完全合理的。像这样的问题是99.99%的废话,所以不要问!