equals方法和hashcode方法

为什么要用到equals和hashcode方法
equals:有时我们紧紧需要比较两个对象是否相等(自己手动调用)
hashcode:是因为我们要将唯一的对象存入到集合中(或者说实际中集合中不能存在重复的值,也需要比较是否存在重复的,例如,hashset、hashmap的键) (程序自己调用)

Object的equals是比较两个对象的内存地址,hashcode方法返回的是一个哈希码值,与内存地址有关,是int值,
然而hashcode方法的算法跟对象本身有关(jdk根据对象的地址或者字符串或者数字算出来的),所以当你重写equals时,对象本身发生变化,当然hashcode也就发生了变化(由 Object 类定义的 hashCode 方法会针对不同的对象返回不同的整数)

A

都没重写之前:

package collectionsFramework;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;

public class HashSetTest {
    public static void main(String[] args) {
        Map<Student,String> m = new HashMap<Student,String>();
        
        m.put(new Student(1,"zhangsan"), "aa");
        m.put(new Student(1,"zhangsan"), "bb");
        m.put(new Student(2,"区分"), "cc");
        
        System.out.println(new Student(1,"zhangsan") == new Student(1,"zhangsan"));
        System.out.println(new Student(1,"zhangsan").equals(new Student(1,"zhangsan")));
        Iterator<Entry<Student, String>> itmap = m.entrySet().iterator();
        while (itmap.hasNext()) {
            System.out.println(itmap.next());
            System.out.println(m.get(new Student(1,"zhangsan")));
        }
        
        System.out.println();
        HashSet<Student> hs = new HashSet<Student>();
        hs.add(new Student(1,"zhangsan"));
        hs.add(new Student(1,"zhangsan"));
        hs.add(new Student(2,"区分"));
        Iterator<Student> itset = hs.iterator();
        while (itset.hasNext()) {
            System.out.println(itset.next());
             System.out.println(m.get(new Student(1, "zhangsan")));
        }

        /*
         * for(Iterator it = m.entrySet().iterator(); it.hasNext();){
         * System.out.println(m.get(new Student(1, "zhangsan"))); }
         */
    }
}

class Student {
    int num;
    String name;

    Student(int num, String name) {
        this.num = num;
        this.name = name;
    }

    public String toString() {
        return num + "+" + name + "+" + this.hashCode() + ";";
    }

}

结果:

false
false
1+zhangsan+33263331;=bb
通过键取得的数据:-------null
1+zhangsan+12677476;=aa
通过键取得的数据:-------null
2+区分+6413875;=cc
通过键取得的数据:-------null

1+zhangsan+28737396;
null
1+zhangsan+27744459;
null
2+区分+6927154;
null


B

仅重写equals

package collectionsFramework;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;

public class HashSetTest {
    public static void main(String[] args) {
        //同上
    }
}

class Student {
    int num;
    String name;

    Student(int num, String name) {
        this.num = num;
        this.name = name;
    }

    public String toString() {
        return num + "+" + name + "+" + this.hashCode() + ";";
    }

    public boolean equals(Object obj) {
        if (null == obj) {
            return false;
        } else {
            if (obj instanceof Student) {
                Student o = (Student) obj;
                if (this.name == o.name && this.num == o.num) {
                    return true;
                }
            }
            return false;
        }
    }

}

结果:

false
true
1+zhangsan+33263331;=bb
通过键取得的数据:-------null
1+zhangsan+12677476;=aa
通过键取得的数据:-------null
2+区分+6413875;=cc
通过键取得的数据:-------null

1+zhangsan+28737396;
null
1+zhangsan+27744459;
null
2+区分+6927154;
null


表面上new Student(1,"zhangsan").equals(new Student(1,"zhangsan")) 为true,但是两个'相同'对象都作为了hashmap的键值,都存进hashset去了,为什么?因为jdk不是像你一样简单的equals,它比较两个对象时还会比较对象的hash码值,只有你重写hashcode()时,使得hashcode一致时,它们才相等,这样造成了,hashset里面有我们认为重复的数据,hashmap有相同的键,使用这个相同的键,去取出value时,因为程序不知道你调用的哪个key,所以无法找到value,垃圾hashset与hashmap就出现了

C

仅重写hashcode

package collectionsFramework;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;

public class HashSetTest {
    public static void main(String[] args) {
        //同上
    }
}

class Student {
    int num;
    String name;

    Student(int num, String name) {
        this.num = num;
        this.name = name;
    }

    public String toString() {
        return num + "+" + name + "+" + this.hashCode() + ";";
    }

    public int hashCode() {
        return num * name.hashCode();
    }

}

结果:

false
false
1+zhangsan+-1432604556;=bb
通过键取得的数据:-------null
1+zhangsan+-1432604556;=aa
通过键取得的数据:-------null
2+区分+1362968;=cc
通过键取得的数据:-------null

1+zhangsan+-1432604556;
null
1+zhangsan+-1432604556;
null
2+区分+1362968;
null


4

都重写:

package collectionsFramework;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;

public class HashSetTest {
    public static void main(String[] args) {
        //同上
    }
}

class Student {
    int num;
    String name;

    Student(int num, String name) {
        this.num = num;
        this.name = name;
    }

    public String toString() {
        return num + "+" + name + "+" + this.hashCode() + ";";
    }

    public boolean equals(Object obj) {
        if (null == obj) {
            return false;
        } else {
            if (obj instanceof Student) {
                Student o = (Student) obj;
                if (this.name == o.name && this.num == o.num) {
                    return true;
                }
            }
            return false;
        }
    }

    public int hashCode() {
        return num * name.hashCode();
    }

}

结果:

false
true
1+zhangsan+-1432604556;=bb
通过键取得的数据:-------bb
2+区分+1362968;=cc
通过键取得的数据:-------bb

1+zhangsan+-1432604556;
bb
2+区分+1362968;
bb

 

从第二段代码的运行结果可以看出,单单只比较只需要重写equals就可以了,

但是new Student(1,"zhangsan")都存进了Hashset(说明对象不相等,hashcode值不一样),并且在hashmap中,m.get(new Student(1, "zhangsan"))得到的是null,

new Student(1, "zhangsan")对应两个值,"aa","bb",矛盾了,不能作为键值

所以此时得同时重写hashcode,之后hashset后面添加一个相同的会覆盖先前先添加的,这样就只添加了一个,而在hashmap中,两个对象是一样的,后一个作为键值。

 

 

posted on 2013-01-21 01:46  lovebeauty  阅读(666)  评论(0编辑  收藏  举报

导航