如何为已有equals方法的ReservationSHC类编写hashcode?equals是否被重写?
一、equals方法是否属于重写?
首先,这个equals方法确实是重写了Object类的equals方法,因为它的方法签名public boolean equals(Object arg0)和Object类的equals方法完全一致。不过没加@Override注解是个不良实践:
- 没有
@Override的话,要是不小心改了方法签名(比如把参数改成ReservationSHC arg0),编译器不会报错,这时候方法就变成重载而非重写,很容易引发逻辑错误。 - 强烈建议加上
@Override注解,让编译器帮你校验方法签名的正确性。
另外,这个equals方法存在违反equals约定的严重问题:
equals约定要求对称性:如果
a.equals(b)为true,那么b.equals(a)必须也为true。
但当前实现里,当ReservationSHC实例的shc等于某个String时,reservationSHC.equals("abc")会返回true,可反过来"abc".equals(reservationSHC)会返回false(因为String的equals方法只比较同类型对象),这直接打破了对称性,会导致HashMap、HashSet这类集合的行为完全异常,这个问题得优先修复。
二、合适的hashCode实现
hashCode的核心约定是:相等的对象必须拥有相同的hashCode,所以实现必须和equals逻辑保持一致。
修复equals后的推荐hashCode实现
先建议修复equals方法,让它只处理同类型对象(符合对称性要求),修改后的equals可以是:
@Override public boolean equals(Object arg0) { if (this == arg0) return true; if (arg0 == null || getClass() != arg0.getClass()) return false; ReservationSHC that = (ReservationSHC) arg0; return Objects.equals(this.shc, that.shc); }
这里用Objects.equals能避免shc为null时抛出空指针异常。
对应的hashCode实现应该完全基于shc字段,因为equals只比较这个字段:
@Override public int hashCode() { return Objects.hash(shc); }
Objects.hash会自动处理shc为null的情况(null的hashCode默认是0),不用手动判空。- 这样所有相等的ReservationSHC实例都会有相同的hashCode,完全符合约定。
如果坚持保留原equals的跨类型比较(不推荐)
要是一定要保留原equals里和String比较的逻辑,那hashCode必须和String的hashCode保持一致——因为当reservationSHC.equals("abc")为true时,它们的hashCode必须相等:
@Override public int hashCode() { return shc != null ? shc.hashCode() : 0; }
但还是强烈不建议这么做,跨类型的equals违反对称性,会让集合类出现各种不可预期的问题。
额外提醒
- 原equals方法没处理
shc为null的情况,要是this.shc或者reservationSHC.getShc()是null,调用equals会直接抛出空指针异常,必须修复。 - 类里的其他字段(比如id、systemGenerated等)没参与equals比较,意味着只要shc相同,哪怕其他字段完全不同,两个实例也会被认为相等,你得确认这是否符合业务逻辑。
内容的提问来源于stack exchange,提问作者user1896796

