聊聊hashcode和equals

基本概念

hashcode:
有人說hashcode就是對象的內存地址,這種說法其實過於絕對,應該是根據不同的jvm實現決定的。 我理解hashcode的作用是返回哈希碼,確定對象在hash表中的位置,所以僅僅當使用散列表的類【hashset, hashmap, hashtable】的時候纔有重寫的意義。如果是非散標的集合(比如list),就只需要重寫equals了。如果不重寫則返回Object中的默認實現。

equals:

說到equals,必須說下”==”,前者是比較對象的內容,後者是比較對象的地址。默認是採用Object中的equals方法,用“==“比較,即比較對象的地址。

舉例說明:

後面就通過四個實例來驗證以上的結論。
假設我們有一個Person類,如果名字相同我們就確認他們是同一個類。

  • 1.不重寫 hashcode和equals方法:
public class Person {

    private String name;
    private Integer age;
    private String desc;

    public Person(){

    }
    public Person(String name,Integer age){
        this.name=name;
        this.age=age;
    }

    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 getDesc() {
        return desc;
    }

    public void setDesc(String desc) {
        this.desc = desc;
    }
}



public class TestHashCode {
    public static void main(String[] args) {
        Person p = new Person("張三", 12);
        Person p2 = new Person("張三", 12);
        System.err.println("==:"+(p == p2));
        System.err.println("equals:"+(p.equals(p2)));
        HashSet<Person> pSet = new HashSet<Person>();
        pSet.add(p);
        pSet.add(p2);
        System.err.println("pSet: "+pSet.size());       

        List<Person> plist=new ArrayList<Person>();
        plist.add(p);
        plist.add(p2);
        System.err.println("plist: "+plist.size());
    }
}

執行結果:
==:false
equals:false
pSet: 2
plist: 2
  • 2.重寫equals方法:
public class Person {

    private String name;
    private Integer age;
    private String desc;

    public Person(){

    }
    public Person(String name,Integer age){
        this.name=name;
        this.age=age;
    }

    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 getDesc() {
        return desc;
    }

    public void setDesc(String desc) {
        this.desc = desc;
    }


    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Person other = (Person) obj;
        if (name == null) {
            if (other.name != null)
                return false;
        } else if (!name.equals(other.name))
            return false;
        return true;
    }
}

public class TestHashCode {
    public static void main(String[] args) {
        Person p = new Person("張三", 12);
        Person p2 = new Person("張三", 12);
        System.err.println("==:"+(p == p2));
        System.err.println("equals:"+(p.equals(p2)));
        HashSet<Person> pSet = new HashSet<Person>();
        pSet.add(p);
        pSet.add(p2);
        System.err.println("pSet: "+pSet.size());       

        List<Person> plist=new ArrayList<Person>();
        plist.add(p);
        plist.add(p2);
        System.err.println("plist: "+plist.size());
    }
}

執行結果:
==:false
equals:true
pSet: 2
plist: 2
  • 3.重寫hashcode方法:
public class Person {

    private String name;
    private Integer age;
    private String desc;

    public Person(){

    }
    public Person(String name,Integer age){
        this.name=name;
        this.age=age;
    }

    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 getDesc() {
        return desc;
    }

    public void setDesc(String desc) {
        this.desc = desc;
    }


    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Person other = (Person) obj;
        if (name == null) {
            if (other.name != null)
                return false;
        } else if (!name.equals(other.name))
            return false;
        return true;
    }

        @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((name == null) ? 0 : name.hashCode());
        return result;
    }
}



public class TestHashCode {
    public static void main(String[] args) {
        Person p = new Person("張三", 12);
        Person p2 = new Person("張三", 12);
        System.err.println("==:"+(p == p2));
        System.err.println("equals:"+(p.equals(p2)));
        HashSet<Person> pSet = new HashSet<Person>();
        pSet.add(p);
        pSet.add(p2);
        System.err.println("pSet: "+pSet.size());       

        List<Person> plist=new ArrayList<Person>();
        plist.add(p);
        plist.add(p2);
        System.err.println("plist: "+plist.size());
    }
}

執行結果:
==:false
equals:false
pSet: 2
plist: 2
  • 4.重寫equals和hashcode方法:
public class Person {

    private String name;
    private Integer age;
    private String desc;

    public Person(){

    }
    public Person(String name,Integer age){
        this.name=name;
        this.age=age;
    }

    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 getDesc() {
        return desc;
    }

    public void setDesc(String desc) {
        this.desc = desc;
    }


    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Person other = (Person) obj;
        if (name == null) {
            if (other.name != null)
                return false;
        } else if (!name.equals(other.name))
            return false;
        return true;
    }

        @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((name == null) ? 0 : name.hashCode());
        return result;
    }
}



public class TestHashCode {
    public static void main(String[] args) {
        Person p = new Person("張三", 12);
        Person p2 = new Person("張三", 12);
        System.err.println("==:"+(p == p2));
        System.err.println("equals:"+(p.equals(p2)));
        HashSet<Person> pSet = new HashSet<Person>();
        pSet.add(p);
        pSet.add(p2);
        System.err.println("pSet: "+pSet.size());       

        List<Person> plist=new ArrayList<Person>();
        plist.add(p);
        plist.add(p2);
        System.err.println("plist: "+plist.size());
    }
}

執行結果:
==:false
equals:true
pSet: 1
plist: 2

- 結果分析:
我們可以看到,以上四種實驗,驗證了幾下幾個結論。
1.“==“”比較是內存地址; 未重寫的對象equals也是比較的內存地址(Object類中的equals方法)
2.hashcode只是針對使用散列表的對象纔有意義,例子中的list就沒有什麼意義,只需要重寫equals就足夠了。
3.對於需要用到散列表結構【比如示例中的hashSet】的對象,必須把hashcode以及equals一起重寫,否則就會有潛藏的bug,見第二種情況,只是重寫了equals,但是沒有達到我們的目標。 因爲對於hashset來說,首先判斷對象的hashcode,如果hashcode不相等,則直接認爲兩對象不相等;如果hashcode相等,則再去判斷equals。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章