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) 编辑 收藏 举报