HashMap使用重写的equals和hashCode方法无法正常工作

4

对不起,关于这个愚蠢的问题,大家:

为什么equals()hashCode()没有被应用?

目前它们只在HashSet中按照我的预期运行。

更新

即使键值5重复了,它也没有调用equalshashCode

我想在值上也应用它。

就像在这个例子中HashSet调用equal和hashCode一样,为什么HashMap甚至在键上也不调用equals和hashCode呢?

更新2-答案

HashMap的键(类 ->HashCode,equals)会被调用。 谢谢所有人。 我有点困惑。 :)

    public class Employee {

        int id;
        String name; 
        int phone;

        public Employee(int id, String name, int phone) {
            this.id = id;
            this.name = name;
            this.phone = phone;
        }    
    // Getter Setter

        @Override
        public boolean equals(Object obj) {

            if (obj == null) {
                return false;
            }
            if (getClass() != obj.getClass()) {
                return false;
            }
            final Employee other = (Employee) obj;
            System.out.println("Employee -  equals" + other.getPhone());
            if (this.id != other.id) {
                return false;
            }
            if ((this.name == null) ? (other.name != null) : !this.name.equals(other.name)) {
                return false;
            }
            if (this.phone != other.phone) {
                return false;
            }
            return true;
        }

        @Override
        public int hashCode() {
            System.out.println("Employee -  hashCode" );
            int hash = 3;
            hash = 67 * hash + this.id;
            hash = 67 * hash + (this.name != null ? this.name.hashCode() : 0);
            hash = 67 * hash + this.phone;
            return hash;
        }
    }

____________________________________________________________________________________

public class MapClass {

    public static void main(String[] args) {
        Map<Integer,Employee> map = new HashMap<Integer,Employee>();
        map.put(1, new Employee(1, "emp", 981));
        map.put(2, new Employee(2, "emp2", 982));
        map.put(3, new Employee(3, "emp3", 983));
        map.put(4, new Employee(4, "emp4", 984));
        map.put(5, new Employee(4, "emp4", 984));
       **//UPDATE**
        map.put(5, new Employee(4, "emp4", 984));            

        System.out.println("Finish Map" + map.size());
        Set<Employee> set = new HashSet<Employee>();

        set.add(new Employee(1, "emp", 981));
        set.add(new Employee(2, "emp2", 982));
        set.add(new Employee(2, "emp2", 982));
        set.add(new Employee(3, "emp3", 983));
        set.add(new Employee(4, "emp4", 984));
        set.add(new Employee(4, "emp4", 984));

        System.out.println(set.size());
    }
}

输出结果为

Finish Map5
Employee -  hashCode
Employee -  hashCode
Employee -  hashCode
Employee -  equals982
Employee -  equals982
Employee -  hashCode
Employee -  hashCode
Employee -  hashCode
Employee -  equals984
Employee -  equals984
4

1
问题到底是什么?请记住,在HashMap中,键是被哈希的,而不是值。 - Guillaume Polet
我该如何为HashMap调用hashCode和equals方法? - Ravi Parekh
Map调用equals和hashCode方法,而且是为Integer键这样做的!如果你想让Map检查Employee的hashCode和/或equals,那么Employee必须是Key而不是Value。 - Hovercraft Full Of Eels
为什么即使key重复,也不会调用hashMap(equals和hascode)? - Ravi Parekh
很高兴你已经搞定了!1+ - Hovercraft Full Of Eels
4个回答

7

即使key的值为5重复了,但它并没有调用equals和hashCode函数。

实际上,它会在key上的整数类型上调用hashCode函数。

我想把这个方法也应用到Value上。

现实情况是:Java HashMap不是这样工作的。它们只检查key是否有重复,而不检查value,这就是它应该的方式。

如果你想在Map中检查Employee的哈希值,则必须将其作为key。没有其他选择。

另一个可能的解决方案是下载其中一个可用的多映射。

编辑以查看它是否调用了hashCode和equals函数,请将Map的key类型更改为以下内容:

class MyInt {
   private Integer i;

   public MyInt(Integer i) {
      this.i = i;
   }

   public Integer getI() {
      return i;
   }

   @Override
   public int hashCode() {
      System.out.println("MyInt HashCode: " + i.hashCode());
     return i.hashCode();
   }

   @Override
   public boolean equals(Object obj) {
      System.out.printf("MyInt equals: [%s, %s]%n", i, obj);
      if (this == obj)
         return true;
      if (obj == null)
         return false;
      if (getClass() != obj.getClass())
         return false;
      MyInt other = (MyInt) obj;
      if (i == null) {
         if (other.i != null)
            return false;
      } else if (!i.equals(other.i))
         return false;
      return true;
   }

   @Override
   public String toString() {
      return i.toString();
   }

}

然后按以下方式填写您的地图:

   Map<MyInt,Employee> map = new HashMap<MyInt,Employee>();
   map.put(new MyInt(1), new Employee(1, "emp", 981));
   map.put(new MyInt(2), new Employee(2, "emp2", 982));
   map.put(new MyInt(3), new Employee(3, "emp3", 983));
   map.put(new MyInt(4), new Employee(4, "emp4", 984));
   map.put(new MyInt(5), new Employee(4, "emp4", 984));
   map.put(new MyInt(5), new Employee(4, "emp4", 984));

你将会看到:

MyInt HashCode: 1
MyInt HashCode: 2
MyInt HashCode: 3
MyInt HashCode: 4
MyInt HashCode: 5
MyInt HashCode: 5
MyInt equals: [5, 5]

@Ravi:如果员工是HashMap的,那么你会看到hashCode方法被调用。请参见我上面的编辑,了解HashMap如何调用hashCode和equals方法。 - Hovercraft Full Of Eels
1
谢谢,我明白了,HashMap的键(类->hashCode)将被调用。 - Ravi Parekh

3

HashMap使用Key值(在您的情况下为Integer)的equals/hashCode。我想这就是你要问的,对吧?

你的Map中出现重复的原因是你为同一个Employee使用了新的Key。

  map.put(4, new Employee(4, "emp4", 345));
  map.put(5, new Employee(4, "emp4", 345));  // You are using 5 as the key
                                             // for the "same" object you did 
                                             // in the previous line

如果你做了类似的事情

  // in main
  addEmployee(new Employee(4, "emp4", 345));
  addEmployee(new Employee(4, "emp4", 345));

  private void addEmployee(Employee e)
  {
     map.put(e.getId(), e);
  }

那么您的收藏中将看不到任何重复的内容。

我想重写hashCode和equals,但在HashMap中,“Equals&hashCode”并没有被重写。我想将其应用到Value上。 - Ravi Parekh
@Ravi:这没有任何意义。HashMap 正常工作。你只是没有理解正在被检查的键。 - Hovercraft Full Of Eels
只是想确认一下,就像在这个例子中 HashSet 调用 equal 和 hashCode 一样,为什么即使对于键,hashMap 也没有被调用。 - Ravi Parekh
1
您提供的代码确实调用了键的equalshashCode方法,但这些键是Integer类型的,而不是Employee类型的。 - Louis Wasserman

3

HashMap使用键作为索引,而不是值。(也就是hashCode(),在上面的代码中可能会调用Integer类的equals())


0

你正在使用一个 HashMap<Integer, Employee>,看起来是这样的,所以 Integer 将被哈希。由于键是 1,2,3,4,5,因此你的 HashMap 的大小应该为 5。


但是当你运行它时,显示大小为5。 - Ravi Parekh

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接