自定义对象作为Map键

时间:2019-04-24 13:03:52

标签: java collections hashmap equals hashcode

我已经读过,如果自定义对象需要作为map的键,则需要覆盖hashcode和equals方法,但是在我的情况下,它的工作原理并不被覆盖。有人可以告诉我出什么问题了吗?

    Map<Student,Integer> map = new HashMap<>();
    Student s1=new Student(1,"A");
    Student s2=new Student(2,"B");
    Student s3=new Student(3,"C");

    map.put(s1,1);
    map.put(s2,2);
    map.put(s1,3);

    for(Student s:map.keySet()) {
        System.out.println(map.get(s) + "->" + s.id + " " +s.name);
    }

正确的输出:

3-> 1 A

2-> 2 B

3 个答案:

答案 0 :(得分:4)

它是equals方法中的properties之一:它是自反的。这意味着

x.equals(x) == true 

对象始终等于自身。在这种情况下,您将中继equals方法的默认实现。

map.put(s1,1); 
map.put(s1,3);

并且因为默认实现是自反的

s1.equals(s1) == true 

1被替换为3

但是,如果您做这样的事情,结果将有所不同

map.put(new Student(1,"A"),3);

s1.equals(new Student(1,"A")); 

您将需要覆盖hashCodeequals才能使其正常工作。

答案 1 :(得分:2)

如果没有覆盖的hashCode或equals方法,则Java将比较对象引用。因此,s1引用与s1引用相同,因此您可以将s1关联值替换为另一个值。

如果您创建的新Student对象的属性值与s1相同,并尝试将其插入到地图中,则会有两个不同的对。

答案 2 :(得分:2)

内置hashCode()equals()可以正常工作。它们与HashMap要求的方式一致(即:如果hashCode()不相同,则equals()将始终返回false)。这是因为每个对象实例本身只会是equal()

但是,这通常不是您想要的。具体来说,在不覆盖这些方法的情况下,具有相同字段的Student的两个实例将不被视为相等。因此,它将打印出三行而不是一行:

Map<Student,Integer> map = new HashMap<>();
Student s1=new Student(1,"A");
Student s2=new Student(1,"A");
Student s3=new Student(1,"A");

map.put(s1,1);
map.put(s2,2);
map.put(s3,3);

for(Student s:map.keySet()) {
    System.out.println(map.get(s) + "->" + s.id + " " +s.name);
}

(注意:从技术上讲,这完全是正确的,但不一定是大多数阅读您的代码的人都会期望的。)