1. 程式人生 > >HashMap, equals, hashCode

HashMap, equals, hashCode

over return 原則 name object類 imp shc turn 官方

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...
{[email protected]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...
{[email protected]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通常就是必須的了。

HashMap, equals, hashCode