HashMap, equals, hashCode

equals和hashCode是Object类中的两个方法。

这两个方法会被所有的类继承,也就是说所有的类都有这两个方法。

这两个方法可以被重写。

 

重写equals和hashCode有一个原则:

如果两个对象是equals的,那么尽量使hashCode相同;

如果两个对象的hashCode相同,那么这两个对象不一定equals。

 

最近有一个人问我一个问题。

给一个Person类追加了一个equals方法,但是没有重写hashCode方法有没有什么问题?

当然没有问题了,但是他说是有问题的。问题出在了HashMap这里。如果把这个Person对象作为key放到HashMap中,value暂且不管,会出问题。

 

以上是环境。尽管他说的不太对,但是有一定的启发。

 

HashMap存在的意义是能够方便的获取某一个key所对应的value。而通过这个key去获取对象的时候会调用这个key的hashCode方法。

public class HashEqualsTester {

    public static void main(String[] args) {
        Person p1 = new Person();
        p1.setId("abc");
        p1.setName("ABC");
        p1.setAge(25);
        p1.setDescription("I am just person 1.");

        Person p2 = new Person();
        p2.setId("abc");
        p2.setName("ABC");
        p2.setAge(25);
        p2.setDescription("I am just person 2.");

        Map<Person, String> map = new HashMap<Person, String>();

        map.put(p1, p1.getDescription());
        map.put(p2, p2.getDescription());

    }

}

class Person {
    private String id;
    private String name;
    private Integer age;
    private String description;

    @Override
    public int hashCode() {
        System.out.println("hashCode called...");
        return 1;
    }
    // get and set
}

  

执行main函数,会打印:

hashCode called...
hashCode called...

但是我们打印map的时候,如:

System.out.println(map);

执行结果为:

hashCode called...
{hash.equals.Person@1=I am just person 2.}

并且,map中只存在一条记录。也就是说当两个对象的hashCode值相同的时候,只保存一个值。

如果hashCode不相同呢?

如果两个对象的hashCode相同,会继续调用对象的equals方法,如果两个对象是equals的,那么也只会在map中存一个值,并且是后一个值。

把代码放一下:

package hash.equals;

import java.util.HashMap;
import java.util.Map;

public class HashEqualsTester {

    public static void main(String[] args) {
        Person p1 = new Person();
        p1.setId("abc");
        p1.setName("ABC");
        p1.setAge(25);
        p1.setDescription("I am just person 1.");

        Person p2 = new Person();
        p2.setId("abc");
        p2.setName("ABC");
        p2.setAge(25);
        p2.setDescription("I am just person 2.");

        Map<Person, String> map = new HashMap<Person, String>();

        map.put(p1, p1.getDescription());
        map.put(p2, p2.getDescription());

        System.out.println(map);

        System.out.println(map.get(p1));
        System.out.println(map.get(p2));

    }

}

class Person {
    private String id;
    private String name;
    private Integer age;
    private String description;

    @Override
    public boolean equals(Object person) {
        System.out.println("equals called...");
        return true;
    }

    @Override
    public int hashCode() {
        System.out.println("hashCode called...");
        return 1;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }
}

执行结果:

hashCode called...
hashCode called...
equals called...
hashCode called...
{hash.equals.Person@1=I am just person 2.}
hashCode called...
I am just person 2.
hashCode called...
equals called...
I am just person 2.

 

话虽如此,这里面仍然有几个东西不太明确。

1,为什么要用一个对象作为map的key呢?

2,知道了这些有什么意义呢?

3,有一本java书籍上说过,除非你有很正当的理由,不然别去重写你的equals和hashCode方法。

=================================

* Note that it is generally necessary to override the {@code hashCode}
* method whenever this method is overridden, so as to maintain the
* general contract for the {@code hashCode} method, which states
* that equal objects must have equal hash codes.

这是java官方的equals中的一段描述,如果对equals方法进行了override的话,重写hashCode通常就是必须的了。

===============================================================

重写了equals方法,而不去重写hashcode并没有什么太大的问题,只不过会造成性能低下。 

posted @ 2017-09-24 10:37  VoctrALs  阅读(185)  评论(0编辑  收藏  举报