您的位置:首页 > 编程语言 > Java开发

Java中hashCode和equals详解

2014-05-16 11:56 387 查看
我们先通过一个例子来看一下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;
	}

	@Override
	public 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值一致,比如开头的程序,我们可以这样重写:

@Override
	public 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;
	}

	@Override
	public 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=习近平]] 只有一个对象,大功告成~!!!!!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: