对于所有对象都适用的equals要求

equals
equals 通用约定
不需要覆盖equals方法的情况
  • 类的每个实例本质上都是唯一的 。
    对于代表活动实体而不是值( value)的类来说确实如此 ,例如 Thread 。 Object 提供的 equals 实现对于这些类来说正是正确的行为 。

值类:值类仅仅是一个表示值的类,例如 Integer 或者 String 。

  • 类没有必要提供“逻辑相等”( logical equality )的测试功能 。

    例如, j ava . util .regex . Pattern 可以覆盖 equals ,以检查两个 Patter口实例是否代表 同 一个
    正则表达式,但是显然这样比较毫无意义。

  • 超类已经覆盖 了 equals , 超类的行为对于这个 类也是合适的 。

​ 例如,大多数的 Set 实现都从 Abstract Set 继承 equals 实现, List 实现从 AbstractList 继
​ 承 equals 实现, Map 实现从 AbstractMap 继承 equals 实现 。

  • 类是私有的 , 或者是包级私有的 ,可以确定它的 equals 方法永远不会 被调用 。

​ 如果你非常想要规避风险,可以覆盖 equals 方法,以确保它不会被意外调用:

@Override
public boolean equals(Object o){
    throw new AssertionError();   //  Method  is  never  called
}

有一种“值类”不需要覆盖 equals 方法,即用实例受控(上述第 l 条)确保“每个
值至多只存在一个对象”的类 。 枚举类型就属于这种类 。 对于这样的类而
言,逻辑相同与对象等同是一回事,因此 Object 的 equals 方法等同于逻辑意义上的
equals 方法。

覆盖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 ) : 对于任何非 nu ll 的 引用值 x 和 y ,只要 equals 的比较操作
    在对象中所用的信息没有被修改,多次调用 x.equals(y )就会一致地返回 true,
    或者一致地返回 false 。
  • 非空性 :对于任何非 null 的引用值 x, x.equals (null )必须返回 false 。
实现高质量 equals 方法的诀窍
  1. 使用 == 操作符检查“参数是否为这个对象的引用” 。 如果是,则返回 true 。 这只
    不过是一种性能优化,如果比较操作有可能很昂贵,就值得这么做。
  2. 使用 instanceof 操作符检查“参数是否为正确的类型” 。 如果不是,则返回 false 。
    一般说来,所谓“正确的类型”是指 equals 方法所在的那个类 。 某些情况下,是指该类 所实现的某个接口 。 如果类实现的接口改进了 equals 约定,允许在实现了该接口的类之间进行比较,那么就使用接口 。 集合接口如 Set 、 List 、 Map 和 Map . Entry 具有这样的特性 。
  3. 把参数转换成正确的类型 。 因为转换之前进行过且 stanceof 测试,所以确保会成功 。
  4. 对于该类中的每个“关键”( significant )域,检查参数中的域是否与该对象中对应的域相匹配 。 如果这些测试全部成功, 则返回 true ;否则返回 false 。

对于既不是 float 也不是 double 类型的基本类型域,可 以使用==操作符进行比较;
对于对象引用域,可以递归地调用 equals 方法;

对于 float 域,可以使用静态、 Float.compare(float, float)方法;

对于 double 域,则使用 Double . compare(double, double ) 。
对 float 和double 域进行特殊的处理是有必要的,因为存在着 Float . NaN 、 - 0.0 f 以及
类似的 double 常量;虽然可以用静态方法 Float.equals 和 Double . equals 对 float 和 double 域进行比较,但是每次比较都要进行自动装箱,这会导致性能下降 。

对于数组域,则要把以上这些指导原则应用到每一个元素上 。 如果数组域中的每个元素都很重要,就可以使用其中一个 Arrays .equals 方法 。
有些对象引用域包含 null 可能是合法的,所以,为了避免可能导致 Null Pointer Excepti on 异常,则使用静态方法 Objects . equals(Object , Object ) 来检查这类域的等同性 。

// Class with a typical equals method
 public final class PhoneNumber {
     
    private final short areaCode,prefix,lineNum ;
     
    public PhoneNumber (int areaCode, int prefix, int lineNum){
     this.areaCode = rangeCheck(areaCod, 999, "area   Code"),
     this.prefix   = rangeCheck(prefix, 999, "pre   fix");
     this.lineNum = rangeCheck (lineNum, 9999, "line   Num");
    }
   private static short rangeCheck (int val , int max, String arg) {
          if (val < 0 ||  val > max)
         throw new  IllegalAgumentException( arg +:+ val );
       return (short) val;
   }
     @Override 
   public boolean equals(Obj ect o) {
       if (o == this)
       return true;
       if (!(o instanceof PhoneNumber))
         return  false ;
    PhoneNumber pn = (PhoneNumber) o;
   return pn.lineNum = = lineNum && pn.prefix = = prefix&& pn.areaCode== areaCode;
}
...// R ema i nde omitted
 }
最后的要求
  • 覆盖 equals 时总要覆盖 hashCode 。
  • 不要企 图让 equals 方法过于 智能 。
  • 不要将 equals 声 明 中 的 Object 对象替换为其他的类型。
// Broken - parameter type must be Object!
public boolean equals(myClass o) {  
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值