Java中equals和hashCode方法的作用

《Effective Java》

equals和hashCode方法是Object类中定义的两个方法:

public native int hashCode();
public boolean equals(Object obj) {
   return (this == obj);
}

本文就这两个方法谈谈它们的作用与联系。

1 equals方法

当我们要比较两个数是否相等时,常常通过==操作符便可得出,但对于两个对象的比较而言,使用==仅仅是比较该两个对象引用是否指向同一个对象,并未涉及对象中成员的比较,这种比较也叫做“浅比较(Shallow Comparison)”;而要实现“深比较(Deep Comparison)”,则要通过覆盖Object中的equals方法了。
但Object中的非final方法都有着明确的通用约定,在覆盖这些方法时,我们是有责任遵循这些约定的,否则,依赖于这些约定的类或方法就无法获得期望的结果。
覆盖equals方法时,需要遵循的约定有:

  • 自反性(reflexive)。对于任何非null的引用值x,x.equals(x)必须返回true。
  • 对称性(symmetric)。对于任何非null的引用值x和y,当且仅当y.equals(x)返回true时,x.equals(y)也必须返回true。
  • 传递性(transitive)。对于任何非null的引用值x、y和z,如果x.equals(y)返回true,并且y.equals(z)也返回true,那么x.equals(z)也必须返回true。
  • 一致性(consistent)。对于任何非null的引用值x和y,只要equals的比较操作在对象中所用的信息没有被修改,多次调用x.equals(y)应付一致地返回true,或者一致地返回false。
  • 对于任何非null的引用值x,x.equals(null)必须返回false。
public class Point {
	
	public int x;
	
	public int y;
	
	public Point() {
		
	}
	
	public Point(int x, int y) {
		this.x = x;
		this.y = y;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (!(obj instanceof Point)) 
			return false;
		Point other = (Point) obj;
		if (x != other.x)
			return false;
		if (y != other.y)
			return false;
		return true;
	}

	public static void main(String[] args) {		
		Point p = new Point(1, 1);
		Point p2 = new Point(1, 1);
		
		System.out.println(p.equals(p2));//输出true
		
		List<Point> list = new ArrayList<>();
		list.add(p);
		System.out.println(list.contains(p2));//输出true
	}
}

2 hashCode方法

hashCode方法会返回对象的一个哈希值,该方法被用于支持基于哈希的集合(如HashMap,HashSet,Hashtable)运作得更好。在覆盖了equals方法的类中,通常也被要求覆盖hashCode方法。
在覆盖hashCode方法时,需要遵循的通用约定有:

  • 在应用程序的执行期间,只要对象的equals方法的比较所用到的信息没有被 修改,那么对同一个对象调用多次,hashCode方法都必须始终如一地返回同一个整数。
  • 如果两个对象根据equals(Object )方法比较是相等的,那么调用这两个对象中任意一个对象的hashCode方法都必须产生同样的整数结果
  • 如果两个对象根据equals(Object)方法比较是不相等的,那么调用这两个对象中任意一个对象的hashCode方法,则不一定要产生不同的整数结果。但给不相等的对象产生不同的结果,有可能提高哈希列表的性能。

在使用HashSet时,如果我们覆盖了equals方法却没有覆盖hashCode方法时会发生什么呢?

	Set<Point> set = new HashSet<>();
	set.add(p);
	set.add(p2);
	
	System.out.println(set.size());//输出2

我们都知道,HashSet存储的是不重复的对象,在上面p.equals(p2)返回true的情况下,p和p2都成功添加了进去。
那么,在我们覆盖hashCode方法之后呢,该方法使用eclipse工具生成:

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + x;
		result = prime * result + y;
		return result;
	}

再次运行,可以看到结果输出是1,HashSet是保持了“不重复的”特性。

3 注意点

  • 我们没有办法在扩展可实例化的类的同时,既增加新的属性成员,同时又遵循equals通用约定,除非愿意放弃面向对象的抽象所带来的优势,或者使用组合而非继承。
  • 覆盖equals方法时,不可以把参数的Object类型换为更具体的类型,这样的做法是重载而不是覆盖。
  • 覆盖时hashCode方法时须排除equals方法比较时没有用到的属性,否则会违反约定的第二条。
  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值