List.contains() 在 .equals() 工作时失败

2022-09-01 05:38:53

我有一个对象,它使用字符串作为等效校验。我希望能够 使用 来检查列表是否包含使用某个字符串的对象。ArrayListTestList.contains()

只是:

Test a = new Test("a");
a.equals("a"); // True

List<Test> test = new ArrayList<Test>();
test.add(a);
test.contains("a"); // False!

等于和哈希函数:

@Override
public boolean equals(Object o) {
    if (o == null) return false;
    if (o == this) return true;
    if (!(o instanceof Test)) {
        return (o instanceof String) && (name.equals(o));
    }
    Test t = (Test)o;
    return name.equals(t.GetName());
}

@Override
public int hashCode() {
    return name.hashCode();
}

我读到这一点,以确保适用于自定义类,它需要重写。因此,对我来说,虽然返回 true,但返回 false,这真是太奇怪了。containsequalsequalscontains

我怎样才能做到这一点?

完整代码


答案 1

仅仅因为当你将 String 传递给它时,你的 's 可能会返回 true,并不意味着 当你向它传递一个实例时,'s 会返回 true。事实上,'s 只有在传递给它的实例是另一个实例时才能返回:TestequalsStringequalsTestStringequalstrueString

public boolean equals(Object anObject) {
    if (this == anObject) {
        return true;
    }
    if (anObject instanceof String) { // the passed instance must be a String
        String anotherString = (String)anObject;
        int n = value.length;
        if (n == anotherString.value.length) {
            char v1[] = value;
            char v2[] = anotherString.value;
            int i = 0;
            while (n-- != 0) {
                if (v1[i] != v2[i])
                    return false;
                i++;
            }
            return true;
        }
    }
    return false;
}

ArrayList的调用,它使用搜索实例的方法(示例中的“a”),而不是 的元素类型(在你的情况下):containsindexOfequalsStringListTest

public int indexOf(Object o) {
    if (o == null) {
        for (int i = 0; i < size; i++)
            if (elementData[i]==null)
                return i;
    } else {
        for (int i = 0; i < size; i++)
            if (o.equals(elementData[i])) // o in your case is a String while
                                          // elementData[i] is a Test
                                          // so String's equals returns false
                return i;
    }
    return -1;
}

答案 2

equals()应始终是可交换的,即 并应始终返回相同的值。或者对称,正如 equals() 的 javadoc 所称:a.equals(b)b.equals(a)

该方法在非空对象引用上实现等价关系:equals

  • 它是自反的:对于任何非空引用值,应返回 。xx.equals(x)true
  • 它是对称的:对于任何非空引用值 xyx.equals(y) 应返回 true 当且仅当 y.equals(x) 返回 true
  • 它是可传递的:对于任何非空引用值 、 、 和 ,如果返回并返回 ,则应返回 。xyzx.equals(y)truey.equals(z)truex.equals(z)true
  • 它是一致的:对于任何非空引用值和 ,一致返回或一致返回的多次调用,前提是不修改对象比较中使用的信息。xyx.equals(y)truefalseequals
  • 对于任何非空引用值,应返回 。xx.equals(null)false

不幸的是,即使是Java运行时库也弄错了这个。 将比较毫秒值,忽略 ,而返回 。Date.equals(Timestamp)TimestampTimestamp.equals(Date)false