Java Hashset.contains() 产生神秘的结果

2022-09-03 17:40:05

我通常不用Java编写代码,但最近我开始别无选择。我可能对如何正确使用HashSet有一些重大误解。因此,我所做的一些事情可能完全是错误的。但是,我很感激您可能提供的任何帮助。所以实际问题:

在我正在编写的一个小程序中,我生成了非常相似的对象,这些对象在创建时将具有非常具体的id(a或在我的上一次迭代中为a)。由于每个对象都会生成新对象,因此我想过滤掉所有已创建的对象。因此,我开始将每个新对象的id放入我的Hash(Set)中,并使用 进行测试,如果之前创建了对象。以下是完整的代码:stringlongHashSet.contains()

// hashtest.java
import java.util.HashSet;

class L {
    public long l;
    public L(long l) {
        this.l = l;
    }
    public int hashCode() {
        return (int)this.l;
    }
    public boolean equals(L other) {
        return (int)this.l == (int)other.l;
    }
}

class hashtest {
    public static void main(String args[]) {
        HashSet<L> hash = new HashSet<L>();
        L a = new L(2);
        L b = new L(2);
        hash.add(a);
        System.out.println(hash.contains(a));
        System.out.println(hash.contains(b));
        System.out.println(a.equals(b));
        System.out.println(a.hashCode() == b.hashCode());
    }
}

产生以下输出:

true
false
true
true    

所以显然,没有使用所提供的功能,或者我对这个概念有一些重大的误解......containsequalsL

我用openjdk(ubuntu中包含的当前版本)和Win7上Oracle的官方当前java进行了测试。

为了完整性,官方java-api文档:HashSet.contains()

public boolean contains(Object o)

如果此集包含指定的元素,则返回此值。更正式地说,当且仅当此集合包含这样的元素时返回 。truetruee(o==null ? e==null : o.equals(e))

http://download.oracle.com/javase/6/docs/api/java/util/HashSet.html#contains(java.lang.Object)

任何想法或建议?


答案 1

您的方法需要采取 .
因为您声明它采用 ,所以它成为一个附加的重载,而不是重写该方法。
因此,当类调用 时,它将解析为基方法。调用 时,调用 重载,因为 和 都声明为 而不是 。equalsObjectLhashSetequalsObject.equalsequalsabLObject

若要防止将来出现此问题,应在重写方法时添加。
这样,如果编译器实际上不是重写,编译器将向您发出警告。@Override


答案 2

你实际上并没有覆盖;相反,您正在定义一个名称相同但参数不同的新方法。请注意,它采用一个参数,而您的 equals 方法采用一个参数。如果重写 equals 方法以采用 a 并在运行时执行必要的类型检查/强制转换,则代码将按预期工作。Object.equalsObject.equalsObjectLObjectL

此外,这就是为什么每当 JRE 支持@Override注释时,您都应该使用它们。这样,如果您打算重写现有方法时意外实现了新方法,编译器将进行投诉。

举个例子,这个等于方法应该可以正常工作。(而且,在不相关的注释中,如果与之比较的对象为 null,它不会失败。

@Override
public boolean equals(Object other) {
    return other != null && other instanceof L && this.l == ((L)other).l;
}