重写Java中equals和hashcode方法的一般规则

参考:
Java核心技术
https://blog.csdn.net/nwpu_geeker/article/details/78760157

Object简介

Object 类是 Java 中所有类的始祖, 在 Java 中每个类都是由它扩展而来的。如果一个类没有明确地指出其超类,Object就被认为是这个类的超类(父类)。Object类声明了以下函数:

1) protected Object clone()        
2) Class<? extends Object> getClass()  
3) String toString()             
4) int hashCode()        
5) boolean equals(Object obj) 
6) void wait()  
7) void wait(long timeout)     
8) void wait(long timeout, int nanos) 
9) void notify()        
10) void notifyAll()  
11)protected void finalize()

其中比较重要且常用的有equals、hashcode、toString、getClass等方法。

1 equals方法

在 Object 类中,equals方法将判断两个对象是否具有相同的引用。这与Java中“==”的功能是一样的。换句话说,Object类中的equals方法并不会比较对象的内容(状态)。正因为如此,其他类往往需要重写equals方法比较对象的内容。例如, 如果两个雇员对象的ID(key)一样, 就认为它们是相等的,此时equals方法比较雇员对象的ID才可以确定2个对象是否相等。

1.1 如何重写equals方法

1)显式参数命名为 otherObject,稍后需要将它转换成另一个叫做other的变量(强制类型转换时用到)。
2)检测 this(隐式参数)与otherObject是否引用同一个对象:

if (this ==otherObject) return true;

实际上,这是一种经常采用的形式。因为计算这个等式要比一个一个地比较类中所有属性要快得多。
3)检测otherObject是否为null, 如果为null,返回false。这项检测是很必要的。

if (otherObject == null) return false;

4)比较this与otherObject是否属于同一个类,此时有2种情况。
a)如果equals的语义在每个子类中有所改变,就使用getClass检测:

if (getClass()  != otherObject.getClass() ) return false;

b)如果所有的子类都拥有统一的语义,即所有子类包括父类都使用相同的属性比较是否相等,就使用instanceof检测:

if (  !(otherObject instanceof ClassName)  ) return false;

5)将 otherObject 强制类型转换为相应的类类型变量:

ClassName other = (ClassName) otherObject

6)开始对所有需要比较的域进行比较。使用“==”比较基本类型域,使用equals比较对象域。如果所有的域都匹配,就返回true;否则返回false。

return field1 == other.field
&& Objects.equals(field2, other.field2)
&& ...

如果在子类中重新定义equals,就需要在子类中的equals方法中首先调用super.equals(other),然后再加上子类特有域比较是否相等。

1.2 工具类Objects的equals方法

 static boolean equals(Object a, Object b)

如果a和b都为null,返回 true ; 如果只有其中之一为 null, 则返回 false ; 否则返 回a.equals(b)。

1.3 对(4)的解释

Java核心技术一书中说,如果子类能够拥有自己的相等概念,那么对称性需求将强制采用getClass进行检测。
这句话的意思是:只要子类所有对应的域相等就认为2个对象相等,则表示子类拥有自己的相等概念。
如果由超类决定相等的概念,那么就使用instanceof进行检测。
也就是说,2个对象是否相等由超类的属性决定,而和子类的属性完全无关时,就使用instanceof。

2 hashcode方法

equals方法与hashcode方法必须保持一致,即2个相等的对象的散列码也应该相等。对象的散列码表示对象的存储地址。

2.1 Objects的hashcode方法

static int hash(Object . .. objects )

返回一个散列码,由提供的所有对象的散列码组合而得到。

static int hashCode(Object a )

如果a为null返回0,否则返回 a.hashCode() 。使用该方法比使用a.hashcode()要好,主要是当a是null时,该方法会抛出异常。

3 示例

假设Manager类继承自Employee类,而Employee类有name,salary和hireDay等属性,而子类Manager新增属性bonus。
Employee类的代码如下:

import java.time.*;
import java.util.Objects;

public class Employee 
{
	private String name;
	private double salary;
	private LocalDate hireDate;

	public Employee(){}
	public Employee(String name,double salary,int year,int month,int day)
	{
		this.name = name;
		this.salary = salary;
		hireDate = LocalDate.of(year, month, day);
	}
	// getter setter等省略
	public void raiseSalary(double byPercent){
		double raise = salary *  byPercent/100;
		salary += raise;
		
	}
	
	@Override
	public boolean equals(Object otherObject) {
		if(this == otherObject) return true;
		if(otherObject == null) return false;
		
		if(getClass() != otherObject.getClass()) return false;
		
		Employee other = (Employee) otherObject;
		
		return Objects.equals(name, other.name)
				&& salary == other.salary
				&& Objects.equals(hireDate, other.hireDate);
	}
	@Override
	public int hashCode() {
		
		return Objects.hash(name,salary,hireDate);
	}
}

Manager类的定义如下:

public class Manager extends Employee {

	private double bonus;
	public Manager(String name,double salary,int year,int month,int day){
		super(name,salary,year,month,day);
		this.bonus = 0;
	}
	
	public double getSalary(){
		double baseSalary = super.getSalary();
		return baseSalary + bonus;
	}
	
	public void setBonus(double b){
		bonus = b;
	}
	
	@Override
	public boolean equals(Object otherObject) {
	// 子类首先调用父类的equals方法
		if( !super.equals(otherObject)) return false;
		Manager other = (Manager)otherObject;
		return bonus == other.bonus;
	}
	
	@Override
	public int hashCode() {
	// 子类首先调用父类的hashcode,然后加上自己属性的hashcode
		return super.hashCode()+17*new Double(bonus).hashCode();
	}
	
}
  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值