Java中hashCode和equals详解

来源:互联网 发布:抱枕淘宝 编辑:程序博客网 时间:2024/05/17 07:56

我们先通过一个例子来看一下Set集合的运用:

class User {private Integer uid;private String uname;/* 无参构造方法 */public User() {}/* 构造方法 */public User(Integer uid, String uname) {this.uid = uid;this.uname = uname;}public Integer getUid() {return uid;}public void setUid(Integer uid) {this.uid = uid;}public String getUname() {return uname;}public void setUname(String uname) {this.uname = uname;}@Overridepublic String toString() {return "User [uid=" + uid + ", uname=" + uname + "]";}}public class HashSetTest {public static void main(String[] args) {/*创建一个Set集合用于存放user*/Collection<User> users = new HashSet<User>();/*往集合中添加user对象*/users.add(new User(1, "习近平"));users.add(new User(1, "习近平"));users.add(new User(1, "习近平"));/*输出集合中的元素*/System.out.println(users);}}

从我们学习Set集合开始,老师就告诉我们,Set集合是不存在相同元素的哈,但是为什么不存在相同元素呢?比如对于上述程序很多人肯定会认为程序输出结果只有一个对象嘛,因为Set集合不能存储相同的对象啊。但是程序的输出结果是这样的:

[User [uid=1, uname=习近平], User [uid=1, uname=习近平], User [uid=1, uname=习近平]]  输出了三个对象。

其实程序输出三个对象的原因也好理解,记得上一篇文章我们提到过java的内存分配问题,new User(XXX);这样new出来的对象是存在堆区的,且他们的地址不一致,很显然他们就不是同一个对象咯。


那么是老师讲的知识点有错吗?不是的,只是我们没有搞透而已,要使得Set集合存储不同的对象,我们就必须重写父类的hashCode()和equals()方法!


我们先通过一个例子来理解一下hashCode:

class A{private Integer id;public A(Integer id) {super();this.id = id;}}class B{private Integer id;public B(Integer id) {super();this.id = id;}/*重写父类的hashCode()方法*/public int hashCode() {return new Integer(id).hashCode();}}public class HashCodeTest {public static void main(String[] args) {/*测试类A对象的hashCode码*/System.out.println("new A(8).hashCode() = " + new A(8).hashCode());System.out.println("new A(8).hashCode() = " + new A(8).hashCode());/*测试类B对象的hashCode码*/System.out.println("\nnew B(8).hashCode() = " + new B(8).hashCode());System.out.println("new B(8).hashCode() = " + new B(8).hashCode());/*测试String类对象的hashCode值*/System.out.println("\nnew String(\"习近平\").hashCode() = " + new String("习近平").hashCode());System.out.println("new String(\"习近平\").hashCode() = " + new String("习近平").hashCode());/*测试字符串常量的hashCode值*/System.out.println("\n\"习近平\".hashCode() = " + "习近平".hashCode());System.out.println("\"习近平\".hashCode() = " + "习近平".hashCode());/*测试Integer对象的hashCode值*/System.out.println("\nnew Integer(8).hashCode() = " + new Integer(8).hashCode());System.out.println("new Integer(8).hashCode() = " + new Integer(8).hashCode());}}

程序输出结果:


从程序的运行结果我们可以看出,String和Integer等这些Java自带的类都重写了hashCode()方法,才导致了他们的hashCode值一样。但是从类A对象和类B对象的hashCode值中我们又可以发现,对于自定义的类型对象,即使对象内容一致,他们的hashCode值也不会相等,因为他们在内存中的地址不一样,就比如程序中类A的对象。但是类B就不同咯,因为我们重写了父类的hashCode()方法,所以B的对象,如果内容相同,他们的hashCode值也会相同。


总而言之:如果希望自己定义的类对象,内容一样,但由于内存空间不一样,你又想他们返回的hashCode一样,那么你就必须重写hashCode()方法!


绕了一大圈,我们还是回到最开始的那个Set集合的程序,程序中违背了我们的意愿,即我们认为的Set集合不能存储相同元素,所以现在我们要使用手段去掉Set集合中重复的元素!

1:

new User(1, "习近平");new User(1, "习近平");new User(1, "习近平");
new出来的这三个显然是不相等的,虽然他们内容相同,但是内存地址不一样【在堆中的位置也就不一致】,所以导致了他们的hashCode值也是不一样的,我们现在的任务就是把这些不同的对象放到一个"桶"里,然后再从这个"桶"里把相同的元素去掉即可(这种解题的思路其实很简单),那么如何把这些内容一致但是内存地址不一样的对象存在一个"桶"里呢?答案我想大家已经知道了,呵呵,,,明显是要重写hashCode()方法嘛!

2:我们已经解决了第一个问题即为什么要重写hashCode()方法,现在我们来解决第二个问题,我们把这些对象都放在一个"桶"里之后,怎么去掉重复的元素呢?首先我们总要比较一下他们的内容吧!呵呵,,,方法还用我说吗?很简单,重写equals()方法即可咯,

3:以上两点我们已经闹清楚了为啥要重写hashCode()和equals()这两个方法,现在我们来讨论该如何重写hashCode()方法,equals()方法的重写在上一篇文章中详细讲解,这里就不再赘述了【如何重写这个问题,其实没必要讲,因为现在的编译器都自带有重写这两个方法的快捷键(至于怎么使用,自己百度哈)】。

重写hashCode()方法,我们的思路就是把这些内容一致的对象,让他们的hashCode值一致,比如开头的程序,我们可以这样重写:

@Overridepublic int hashCode() {/*把所有内容以字符串的形式捆绑在一起,然后直接调用hashCode()方法即可*/return new String(uid + uname).hashCode();}


4:这里我们在讨论一个问题:什么样的集合要重写hashCode()和equals()方法,说实话,这个自己试验一下就OK了,总结一点就是:HashTable、HashSet、HashMap这样带有Hash的集合都必须同时实现hashCode()和equals()方法,其他的集合倒是没这个要求!!!!


最后来完善一下开头的程序【这里使用编译器的快捷键来重写equals()和hashCode()方法】:

class User {private Integer uid;private String uname;/* 无参构造方法 */public User() {}/* 构造方法 */public User(Integer uid, String uname) {this.uid = uid;this.uname = uname;}public Integer getUid() {return uid;}public void setUid(Integer uid) {this.uid = uid;}public String getUname() {return uname;}public void setUname(String uname) {this.uname = uname;}/*重写父类的hashCode()方法*/public int hashCode() {final int prime = 31;int result = 1;result = prime * result + ((uid == null) ? 0 : uid.hashCode());result = prime * result + ((uname == null) ? 0 : uname.hashCode());return result;}/*重写父类的equals()方法*/public boolean equals(Object obj) {if (this == obj)return true;if (obj == null)return false;if (getClass() != obj.getClass())return false;User other = (User) obj;if (uid == null) {if (other.uid != null)return false;} else if (!uid.equals(other.uid))return false;if (uname == null) {if (other.uname != null)return false;} else if (!uname.equals(other.uname))return false;return true;}@Overridepublic String toString() {return "User [uid=" + uid + ", uname=" + uname + "]";}}public class HashSetTest {public static void main(String[] args) {/*创建一个Set集合用于存放user*/Collection<User> users = new HashSet<User>();/*往集合中添加user对象*/users.add(new User(1, "习近平"));users.add(new User(1, "习近平"));users.add(new User(1, "习近平"));/*输出集合中的元素*/System.out.println(users);}}

上述程序重写了equals()和hashCode()方法之后,Set集合中就没有重复的元素了,程序输出结果:

[User [uid=1, uname=习近平]]   只有一个对象,大功告成~!!!!!



0 0
原创粉丝点击