8

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

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

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

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

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

4

5 回答 5

23

最有可能的是,您只是忘记了在您的类型中覆盖equals()和。是什么检查。hashCode()equals()contains()

Javadoc

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

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

(如果你没有覆盖equalsand hashCode,使用你的类型作为 a 中的键HashMap同样是徒劳的。)


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

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

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

于 2009-06-12T14:29:03.437 回答
14

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

public boolean equals(Foo f)

你需要

public boolean equals(Object o)

以及覆盖 Object.equals。

这将适合 "equals 有效但 contains 不适用,因为您的测试可能会调用强类型的 equals,但 ArrayList 不会。

于 2009-06-12T14:34:17.327 回答
3

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

于 2009-06-12T14:29:50.143 回答
2

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

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

我的建议是检查您实际上是否正确覆盖了 equals() 和 hashCode() 以及它们的签名是否与 Object 类中的签名匹配。

于 2009-06-12T14:42:00.957 回答
0

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

于 2009-06-12T14:30:41.937 回答