虽然哈希码不同,但Java对象是相同的

时间:2012-10-13 18:09:29

标签: java equals hashcode

在阅读equals()和hashcode()时,我开始知道如果两个对象相等,那么它们的哈希码必须相等,但反之亦然。

但是下面的例子没有反映这一点。

class Employee{

  private String name;

  Employee(String name){
    this.name = name;
  }

  @Override
  public boolean equals(Object obj) {           
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Employee other = (Employee) obj;
        if (name == null) {
            if (other.name != null)
                return false;
        } else if (!name.equals(other.name))
            return false;
        return true;
    }

}

现在,如果我创建两个Employee对象

Employee e1 = new Employee("hi");
Employee e2 = new Employee("hi");

如果我这样做,e1.equals(e2),它会返回 true ,即使它们的哈希码不同,这在打印时很明显,e1.hashcode()e2.hashcode()

有人可以解释一下吗?

4 个答案:

答案 0 :(得分:10)

您需要覆盖hashcode方法并提供与equals签订合同的实现。

   @Override
    public int hashCode() {
        return name == null ? 0 : name.hashCode();
    }
  • 如果某个类覆盖equals,则必须覆盖hashCode
  • 当它们都被覆盖时,equalshashCode必须use the same set of fields
  • 如果两个对象为equal,则其hashCode值必须为equal
  • 如果对象为immutable,则hashCode是缓存的候选对象 和lazy initialization

您可以阅读有关实施哈希码here

的信息

如果不覆盖该方法,将使用Object类中的默认行为。

  

尽可能合理,Object类定义的hashCode方法确实为不同的对象返回不同的整数。 (这通常通过将对象的内部地址转换为整数来实现,但JavaTM编程语言不需要此实现技术。)

基于哈希的[HashMap,HashSet,Hashtable,LinkedHashSet,WeakHashMap]集合将使用hashCode()在存储桶中查找/存储对象,然后他们将调用equals()

答案 1 :(得分:4)

这是因为,每次覆盖equals方法时,您还必须覆盖hashcode方法。

否则,您的对象将根据您的代码进行比较,但它们的HashCode将根据Object类中的预定义算法进行计算。

注意: - 一般而言,您在检查objects是否等于时考虑了所有参数,您应该使用all those parameters来计算{{1}每个hashcodes

请参阅this very good post,其中介绍了objectequals方法的使用。

从这篇文章中引用一行,我已经在上面描述过: -

  

使用同一组字段来计算您在hashcode方法中使用的hashcode

让我们看看下面的Demo来理解上面的陈述: -

equals

所以,如果两个对象具有相同的public class Demo { private String str; private String name; public boolean equals(Object obj) { // Suppose you compare two objects based on length of their name variable // If name equals, object are equal if (obj instanceof Demo) { return this.name.equals(((Demo)obj).name); } return false; } // ****** Badly Overrided hashcode ******* public int hashcode() { // But you calculate hashcode using both the fields // You should never use this kind of code in hashcodes. // Use complex algorithm which gives you distinct result for // objects that are not equal. return str.length + name.length; } } ,那么它们将是相同的,但如果它们的name字段具有不同的str,那么它们的length将是不同。

这就是为什么你应该总是在hashcodessame fields计算中使用equals

答案 2 :(得分:0)

您还需要覆盖hashCode以获得您期望的行为。 Object.hashCode的默认实现可能会返回对象引用,但根据the docs,这不是必需的。

如果不覆盖hashCode,你就不能指望专门的结果;这类似于覆盖equals

答案 3 :(得分:0)

你应该覆盖hashcode方法。 如果一个类重写equals,它必须覆盖hashCode 当它们都被重写时,equals和hashCode必须使用相同的字段集 如果两个对象相等,那么它们的hashCode值也必须相等 如果对象是不可变的,则hashCode是缓存和延迟初始化的候选者