【问题标题】:Best way to use contains in an ArrayList in Java?在 Java 的 ArrayList 中使用包含的最佳方法?
【发布时间】:2010-11-02 11:35:20
【问题描述】:

我在 Java 中有一个 ArrayList,它由一个包含两个字符串和一个整数的类型组成。我可以成功测试此 ArrayList 的一个元素是否等于另一个元素,但我发现 contains 方法失败。我相信这是因为我的类型不是原始的。

现在我看到了两个替代方案,我想知道哪个是最好的选择:

  1. 通过遍历 ArrayList 并测试每个元素与我正在寻找的元素的相等性,然后打破循环,来实现我自己的 contains 方法。

  2. 或者使用我类型的 HashMap 作为键,以整数作为值,而不是使用 ArrayList。这里我可以使用 containsKey 方法来检查一个元素是否已经存在于 HashMap 中。

方法#2的唯一警告是,在我的情况下,该值在很大程度上是多余的。

【问题讨论】:

  • 查看 ArrayList 的源代码,你会发现实现已经很简单了。

标签: java arraylist contains


【解决方案1】:

很可能,您只是忘记在您的类型中覆盖equals()hashCode()equals()contains() 检查的内容。

来自Javadoc

如果此列表包含指定元素,则返回 true。更正式地,返回true 当且仅当此列表包含至少一个元素e 使得(o==null ? e==null : o.equals(e))

由于equals 的默认实现会测试引用相等性,因此它不适合像这样的自定义数据类型。

(如果您没有覆盖 equalshashCode,那么在 HashMap 中使用您的类型作为键同样是徒劳的。)


编辑:请注意,要覆盖,您必须提供确切签名。

class MyDataType {
    public boolean equals(MyDataType other) { // WRONG!
        ...
    }
    public boolean equals(Object other) { // Right!
        ...
    }
}

这是使用@Override 注释的一个非常有力的论据;如果使用 @Override 注释,第一个示例将在编译时失败。

【讨论】:

  • 在我的课堂上,我指定了一个 equals 方法: private boolean equals(HierarchicalTreemapElement hte) { if ((this.getChild().equals(hte.getChild())) && (this.getParent() .equals(hte.getParent()) && (this.getQuantity() == (hte.getQuantity()))))) { return true; } 否则 { 返回假;但是如果使用 arraylist,包含仍然会失败。 hashCode 我需要做什么?
  • 你错误地覆盖了 equals(),就像 Jon Skeet 说的那样。在方法签名前面放一个@Override注解只是为了确定(如果不正确,会产生编译错误)。
  • 对于 hashCode,如果你已经覆盖了它,它可能就足够了。如果你没有,你绝对应该;覆盖 equals() 应该总是 意味着覆盖 hashCode()。
  • 除了始终使用@Override 注释之外,我建议您调整编译器设置,以便在您不使用它时生成错误。
  • 注意你的等号签名有两个问题:范围不正确(必须是公共的),类型不正确(必须接受对象)。
【解决方案2】:

你重写了equals方法吗?这是使包含正常工作所必需的。

【讨论】:

    【解决方案3】:

    也许改用 Integer 类?然后你可以做对象比较

    【讨论】:

      【解决方案4】:

      我的猜测是您只编写了一个“强类型”equals 方法,而不是覆盖equals(Object)。换句话说,如果你有:

      public boolean equals(Foo f)
      

      你需要

      public boolean equals(Object o)
      

      以及覆盖 Object.equals。

      这符合“equals 有效,但 contains 无效,因为您的测试可能调用强类型的 equals,但 ArrayList 没有。

      【讨论】:

      • 要扩展“通过测试但失败”评论,请注意,如果您正在测试 MyClass#equals,您应该使用针对 Object#equals 的调用,传递一个对象。 (记下去修复他的单元测试,因为他认为他做的不对)。
      • 嗯...我不确定我的答案是否真的比mmyers的答案添加了任何内容。 Tetsujin no Oni:你想把你的评论复制到那个答案,然后我可以删除这个吗?
      【解决方案5】:

      请记住,如果您不重写 equals() 方法,那么您的类型的两个对象只有在该对象的 相同实例 时才相等。 ArrayList 类使用这个方法来检查它是否包含给定的对象。此外,您需要完全匹配签名,这意味着它必须将 Object 作为参数,而不是 Foo。

      此外,Object 合约规定,无论何时覆盖 equals(),都必须覆盖 hashCode()。如果您不这样做,则 HashMap 或 HashSet 不会将您的两个对象识别为相等,即使 ArrayList 确实如此(HashMap 检查相同的哈希,然后在它们上调用 equals() 以检查实际相等)。因此,如果 ArrayList 说两个项目不相等,那么 HashMap 也不可能。这意味着您的第二个解决方案不起作用。

      我的建议是检查您是否确实正确地覆盖了 equals() 和 hashCode(),并且它们的签名与 Object 类中的签名匹配。

      【讨论】:

        猜你喜欢
        • 2012-10-18
        • 2010-10-14
        • 2020-11-06
        • 1970-01-01
        • 2010-10-08
        • 2011-07-20
        • 1970-01-01
        • 2011-12-23
        • 2011-04-26
        相关资源
        最近更新 更多