Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/342.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 重写equals()时重写hashCode()_Java - Fatal编程技术网

Java 重写equals()时重写hashCode()

Java 重写equals()时重写hashCode(),java,Java,可能重复: 我读到,当重写equals()时,应该始终使用code() 有人能举一个实际的例子说明为什么它可能是错误的吗? i、 e.重写equals()而不是hashCode()时可能出现的问题 每当我们重写equals()时,是否有必要编写一个健壮的hasCode()函数?或者一个微不足道的实现就足够了 比如说, 下面这种糟糕的实现足以满足equals()和hashCode()之间的约定 equals()和hashCode()在某些集合中结合使用,例如HashSet和HashMap,因此您

可能重复:

我读到,当重写equals()时,应该始终使用code()

有人能举一个实际的例子说明为什么它可能是错误的吗? i、 e.重写equals()而不是hashCode()时可能出现的问题

每当我们重写equals()时,是否有必要编写一个健壮的hasCode()函数?或者一个微不足道的实现就足够了

比如说,

下面这种糟糕的实现足以满足equals()和hashCode()之间的约定

equals()
hashCode()
在某些集合中结合使用,例如
HashSet
HashMap
,因此您必须确保如果使用这些集合,则根据合同覆盖
hashCode

如果根本不重写
hashCode
,那么
HashSet
HashMap
就会出现问题。特别是,两个“相等”的对象可以放在不同的哈希桶中,即使它们应该相等

如果您确实重写了hashCode,但做得很差,那么您将遇到性能问题。
HashSet
HashMap
的所有条目都将放在同一个存储桶中,您将失去O(1)性能,取而代之的是O(n)。这是因为数据结构本质上变成了一个线性检查的链表

至于在这些条件之外破坏程序,这是不可能的,但您永远不知道API(特别是在第三方库中)何时会依赖于此合同。对于未实现其中任何一个的对象,都支持该契约,因此可以想象,库可能在某个地方依赖它,而不使用散列桶


在任何情况下,实现一个好的
hashCode
都很容易,尤其是在使用IDE的情况下。Eclipse和Netbeans都能够以遵循所有契约的方式为您生成
equals
hashCode
,包括
equals
的逆规则(断言
a.equals(b)==b.equals(a)
)。您所需要做的就是选择要包含的字段并执行。

这两个
equals
hashcode
都基于对象的唯一性原则。如果
equals
返回
true
两个对象的hashcode必须相同,否则基于hash的结构和算法可能会有未定义的结果

考虑一个基于哈希的结构,例如
哈希映射
hashcode
将被调用作为获取密钥引用的基础,而不是
等于
,这使得在大多数情况下无法找到密钥。此外,
hashcode
的糟糕实现将产生影响性能的冲突(多个对象具有相同的
hashcode
,哪一个是“正确的”对象?)

IMHO,重写
等于
哈希代码
(而不是同时重写两者)应该被视为代码气味,或者至少是潜在的bug源。也就是说,除非你100%确定它迟早不会影响你的代码(我们什么时候这么确定?)


注意:有各种库通过使用
equals
hashcode
构建器来支持这一点,就像
HashcodeBuilder
equalBuilder
您的简单实现是正确的,但会破坏基于哈希的集合的性能


如果类的两个不同实例比较相等,那么默认实现(由
对象提供)将破坏契约。

我建议阅读Joshua Bloch的“有效Java”第3章“所有对象通用的方法”。没有人能比他解释得更好。他领导了许多Java平台功能的设计和实现。

以下是一些代码,说明了不实现hashCode()可能会引入的错误:Set.contains()将首先检查对象的hashCode(),然后检查.equals()。因此,如果不同时实现这两个功能,.contains()将无法以直观的方式运行:

public class ContainsProblem {

// define a class that implements equals, without implementing hashcode
class Car {
    private String name;

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof Car)) return false;
        Car car = (Car) o;
        if (name != null ? !name.equals(car.name) : car.name != null) return false;
        return true;
    }

    public String getName() {return name;}

    public Car(String name) { this.name = name;}
}

public static void main(String[] args) {
    ContainsProblem oc = new ContainsProblem();

    ContainsProblem.Car ford = oc.new Car("ford");
    ContainsProblem.Car chevy = oc.new Car("chevy");
    ContainsProblem.Car anotherFord = oc.new Car("ford");
    Set cars = Sets.newHashSet(ford,chevy);

    // if the set of cars contains a ford, a ford is equal to another ford, shouldn't
    // the set return the same thing for both fords? without hashCode(), it won't:
    if (cars.contains(ford) && ford.equals(anotherFord) && !cars.contains(anotherFord)) {
        System.out.println("oh noes, why don't we have a ford? isn't this a bug?");
    }
}
}

@是的,我看到所有的值都在一个散列桶中。如果我们不考虑性能,还有其他问题吗?或者更准确地说,它在任何情况下都会破坏程序的功能吗?据我所知,它不会破坏任何东西。我相信您不会在集合中使用它。在Java 7中,还有一个类及其散列方法。@Brian确实!我太习惯Apache Commons了,以至于忘了那个;)谢谢你的回答。我认为,您已经给出了一个公平的解释,当它可能是一个执行不佳的问题时。
public class ContainsProblem {

// define a class that implements equals, without implementing hashcode
class Car {
    private String name;

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof Car)) return false;
        Car car = (Car) o;
        if (name != null ? !name.equals(car.name) : car.name != null) return false;
        return true;
    }

    public String getName() {return name;}

    public Car(String name) { this.name = name;}
}

public static void main(String[] args) {
    ContainsProblem oc = new ContainsProblem();

    ContainsProblem.Car ford = oc.new Car("ford");
    ContainsProblem.Car chevy = oc.new Car("chevy");
    ContainsProblem.Car anotherFord = oc.new Car("ford");
    Set cars = Sets.newHashSet(ford,chevy);

    // if the set of cars contains a ford, a ford is equal to another ford, shouldn't
    // the set return the same thing for both fords? without hashCode(), it won't:
    if (cars.contains(ford) && ford.equals(anotherFord) && !cars.contains(anotherFord)) {
        System.out.println("oh noes, why don't we have a ford? isn't this a bug?");
    }
}
}