对于所有对象都通用的方法equals、hashCode

呵呵再补充下,摘录自我的wiki(读

笔记):

 

 

对于所有对象都通用的方法

 

  • Object中的方法:equals,hashCode,toString,clone 和 finalize都有明确的通用约定,所以我们需要遵守,因为不少的类都是按照通用约定来工作的

 

覆盖equals时请遵守通用约定

 

  • 覆盖equals方法有讲究的
  • 一下任意条件满足,都不应该覆盖equals
    1. 类的每个实例本质上都是唯一的,如:Thread
    2. 不关心类是否提供了“逻辑相等”的测试功能:如java.util.Random.equals
    3. 超类已经覆盖了equals,并且子类认为是合适的,如:Map的equals实现继承了?AbstractMap.equals,List的equals实现继承了?AbstractList的equals

  • 类是私有的或是包级私有的,可以确定永远不会被调用equals方法: 需要覆盖equals:throw new ?AssertionError("不要调用我");

  • 如果类有自有的“逻辑相等”就需要覆盖equals方法了
  • equals通用约定:
    1. 自反性:对于任何非空x,x.equals(x)==true
    2. 对称性:对于任何非空x、y,x.equals(y)==y.equals(x);
    3. 传递性:对于任何非空x、y、z,如果x.equals(y)==true、y.equals(z)==true那么x.equals(z)==true;
      1. java.sql.Timestamp和java.util.Date的问题:"鉴于 Timestamp 类和上述 java.util.Date 类之间的不同,建议代码一般不要将 Timestamp 值视为 java.util.Date 的实例。Timestamp 和 java.util.Date 之间的继承关系实际上指的是实现继承,而不是类型继承。"
    4. 一致性:只要x、y没有修改过,那么每次执行x.equals(y)都获得相同的结果
      1. java.net.URL.equals的调用依赖于网络,每次调用它们的内在可能变化
    5. 对于非空x: x.equals(null)==false
  • 高质量的equals方法
    1. 使用==检查参数是否为这个对象的引用:if (o == this) return true;
    2. instance of进行类型检查
    3. 把参数转化为正确的类型
    4. 每个关键域检查它们是否匹配
      1. 非float和double的基本类型直接==比较
      2. float使用Float.compare比较
      3. double使用Double.compare比较
      4. 对于对象引用直接调用equals比较
      5. 如果是数组域,如果每个元素都是关键域,那么每一个都要比较,jdk1.5后可以通过Arrays.equals解决
    5. 注意比较顺序带来的性能影响:最易变的先比较
    6. 写完equals问问:是否对称、传递、一致
      1. 覆盖equals时总要覆盖hashCode
      2. 不要企图让equals过于智能
      3. 不要讲equals中的参数替换为其他类型,这不是覆盖而是重载,所以需要@Override注解

 

覆盖equals时总要覆盖hashCode

 

  • hashCode 的常规协定是:
    1. 在 Java 应用程序执行期间,在对同一对象多次调用 hashCode 方法时,必须一致地返回相同的整数,前提是将对象进行 equals 比较时所用的信息没有被修改。从某一应用程序的一次执行到同一应用程序的另一次执行,该整数无需保持一致。
    2. 如果根据 equals(Object) 方法,两个对象是相等的,那么对这两个对象中的每个对象调用 hashCode 方法都必须生成相同的整数结果。
    3. 如果根据 equals(java.lang.Object) 方法,两个对象不相等,那么对这两个对象中的任一对象上调用 hashCode 方法不 要求一定生成不同的整数结果。但是,程序员应该意识到,为不相等的对象生成不同整数结果可以提高哈希表的性能。
  • hashCode生成简单办法:计算所有的关键域,排除可由其他关键域计算得到的域
    1. 把非0的常数值保存到result中,如17
    2. 对于每一个关键域f(equals中涉及的每个域),完成以下步骤:
      1. 为该域计算int型散列码c:
        1. boolean return f?1:0
        2. byte、char、sort或int return f;
        3. long return (int)(f^(f>>>32))

        4. float return Float.floatToIntBits(f)
        5. double return Double.doubleToLongBits(f)再作为long型来计算散列值
        6. 引用对象return null?0:f.hasCode();
        7. 如果是数组,递归处理每一个元素
      2. 合并result = 31 * result + c
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值