【问题标题】:Who calls the equals method of the class while putting the elements into the HashMap?谁在将元素放入HashMap时调用了类的equals方法?
【发布时间】:2019-11-02 06:08:56
【问题描述】:

我是 Java 新手(非常新)。 我试图了解 HashMap 和类的 equals 方法以及它如何覆盖重复项。 请看以下代码:

public class Student {

    Integer StudentId;
    String Name;
    String City;

    public Student(Integer studentId, String name, String city) {
        super();
        StudentId = studentId;
        Name = name;
        City = city;
    }

    public Integer getStudentId() {
        return StudentId;
    }

    public String getName() {
        return Name;
    }

    public String getCity() {
        return City;
    }




    @Override
    public int hashCode() {
        System.out.println("haschode is called for " + this);

        final int prime = 31;
        int result = 1;
        result = prime * result + ((StudentId == null) ? 0 : StudentId.hashCode());
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        System.out.println("equals is called for " + this);

        if (this == obj)
            return true;

        if (obj == null)
            return false;

        if (getClass() != obj.getClass())
            return false;

        Student other = (Student) obj;

        if (StudentId == null) {
            if (other.StudentId != null)
                return false;

        } else if (!StudentId.equals(other.StudentId))
            return false;

        return true;
    } 


    @Override
    public String toString() {
        return "\n Student [StudentId=" + StudentId + ", Name=" + Name + ", City=" + City + "] \n";
    }

    public static void main(String[] args) {
        // TODO Auto-generated method stub


         Map<Student, String> myMap = new HashMap<Student, String>();

         myMap.put(new Student(1, "andy", "p"), "Great");     //Line 1
         myMap.put(new Student(2, "sachin", "m"), "Better");
         myMap.put(new Student(3, "dev", "s"), "Good");
         myMap.put(new Student(1, "andy", "p"), "Excellent"); // Line 4

         System.out.println(myMap);


    }

}

现在,main() 中编写的代码仅在我编写代码以再次放置相同的键时调用 equals 方法,即“第 4 行”(请参阅​​我的代码缩进)。

为什么“第 2 行”和“第 3 行”没有调用 equals 方法?? 它应该为每个 put 行调用 equals .... 正确吗?

我在这里缺少一些理解,并留下了一些问题: (1) 为什么每个put都不调用equals方法来检查类成员的相等性? (2) 谁触发了Student类equals方法的调用?

【问题讨论】:

  • 我在 main() 中没有看到像 equals() 这样的代码
  • 先生,第 4 行调用了 Student 类中编写的 equals() 方法。我不明白你的问题。

标签: java java-8 hashmap


【解决方案1】:

如果哈希码不同,则没有调用equals的情况。查看 HashMap() 的代码。如果哈希值相同,则调用 equals。

【讨论】:

    【解决方案2】:

    如果hashCode() 结果不同,则不会调用equals()。只有第 1 行和第 4 行相同(相同的学生 ID 为 1),因此为此调用了 equals()

    注意hashCode() may be the same for two objects that aren't equals(), but two equals() objects must never have a different hashCode():

    • 如果两个对象根据 equals(Object) 方法相等,则对两个对象中的每一个调用 hashCode 方法必须产生相同的整数结果。
    • 不要求如果根据equals(java.lang.Object) 方法两个对象不相等,则对两个对象中的每一个调用hashCode 方法必须产生不同的整数结果。但是,程序员应该意识到,为不相等的对象生成不同的整数结果可能会提高哈希表的性能。

    所以最初不同的哈希码足以在之后不调用equals()

    【讨论】:

      【解决方案3】:

      它应该为每个 put 行调用 equals .... 正确吗?

      没有。 HashMap 只有在现有键和put 中给定的键之间遇到散列冲突 后才会调用equals

      换个说法,它首先调用hashCode来确定将密钥放入哪个“哈希桶”,如果目标桶内已经有密钥,则使用equals比较桶中的密钥是否相等.

      由于Student.hashCode()的值仅基于ID,因此在插入过程中,map只需要在遇到与插入的ID相同的Student键时调用equals即可。如果没有现有密钥与插入的密钥具有相同的hashCode,则无需调用equals

      这使得HashMap 在插入过程中非常高效。这也是hashCodeequals 之间存在契约的原因:如果equals 定义的两个对象相等,则它们也必须具有相同的hashCode(但不一定反之亦然)。

      【讨论】:

      • @user2746466 如果有任何答案可以解决您的问题,那么您需要考虑接受其中一个作为正确答案。
      【解决方案4】:

      正如您在运行代码时所见,每次调用 .put() 都会调用 hashcode()

      基本上,每个put() 操作都会调用哈希码,如果它是唯一的,则可以在映射中放置一个新元素 - 正如hashcode() 的条件之一所说,不同的哈希码总是代表不同的对象。然而,不同的对象并不总是有不同的哈希码。因此,如果两个对象的 hashcode 相同,hashmap 必须使用equals() 检查对象是否相等。

      【讨论】:

        【解决方案5】:

        基于 hash 的地图的全部目的是对 hash 值进行操作(为了提高效率)。

        地图首先关心的是不同的哈希值。因此,只要任何“传入”键具有(到目前为止)未知的散列,相等性就无关紧要。

        只有当您遇到 冲突 哈希时,传入的键实际上是 不同 键还是 相同 键才重要.在第一种情况下,您向地图添加一个新的键/值对,在第二种情况下,您更新一个具有潜在新值的已存储键!

        因此,调用equals() 仅发生在 Map 实现必须确定具有相同哈希的两个键是否相等的情况。

        【讨论】:

          【解决方案6】:

          如果您想了解hashCodeequals 方法如何处理选定的值, 创建以下地图:

          Map<Key, Value> map = new HashMap<>();
          

          然后创建以下类的实例并使用它们来填充地图。我推荐使用 String 作为两个类的对象,因为我在这两个类中都使用了它的 equals 方法。

          请注意,您提供了要返回的 hashCode。这允许它相同或不同,因此您可以看到地图在不同情况下的行为。

          class Value {
             private Object obj;
             private int hashCode;
          
             public Value(Object obj, int hashCode) {
                this.obj = obj;
                this.hashCode = hashCode;
             }
          
             public int hashCode() {
                System.out.println("Value: hashCode is called - " + hashCode);
                return hashCode;
             }
          
             public boolean equals(Object o) {
                System.out.println("Value: equals is called - " + obj);
                return obj.equals(o);
             }
          
             public String toString() {
                return "Value: obj = " + obj + ", hashCode = " + hashCode;
             }
          }
          class Key {
             private Object obj;
             private int hashCode;
          
             public Key(Object obj, int hashCode) {
                this.obj = obj;
                this.hashCode = hashCode;
             }
          
             public int hashCode() {
                System.out.println("Key: hashCode is called - " + hashCode);
                return hashCode;
             }
          
             public boolean equals(Object o) {
                System.out.println("Key: equals is called - " + obj);
                return obj.equals(o);
             }
          
             public String toString() {
                return "Key: obj = " + obj + ", hashCode = " + hashCode;
             }
          }
          
          

          【讨论】:

            【解决方案7】:

            可以阅读JDK 1.7中HashMap.java的源码。

            你会明白你问的问题。

            看完HashMap的源码后,其他答案会更有帮助。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2015-08-31
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2020-02-09
              相关资源
              最近更新 更多