呵呵再补充下,摘录自我的wiki(读
笔记):
对于所有对象都通用的方法
- Object中的方法:equals,hashCode,toString,clone 和 finalize都有明确的通用约定,所以我们需要遵守,因为不少的类都是按照通用约定来工作的
覆盖equals时请遵守通用约定
- 覆盖equals方法有讲究的
- 一下任意条件满足,都不应该覆盖equals
-
类是私有的或是包级私有的,可以确定永远不会被调用equals方法: 需要覆盖equals:throw new ?AssertionError("不要调用我");
- 如果类有自有的“逻辑相等”就需要覆盖equals方法了
- equals通用约定:
- 自反性:对于任何非空x,x.equals(x)==true
- 对称性:对于任何非空x、y,x.equals(y)==y.equals(x);
- 传递性:对于任何非空x、y、z,如果x.equals(y)==true、y.equals(z)==true那么x.equals(z)==true;
- java.sql.Timestamp和java.util.Date的问题:"鉴于 Timestamp 类和上述 java.util.Date 类之间的不同,建议代码一般不要将 Timestamp 值视为 java.util.Date 的实例。Timestamp 和 java.util.Date 之间的继承关系实际上指的是实现继承,而不是类型继承。"
- 一致性:只要x、y没有修改过,那么每次执行x.equals(y)都获得相同的结果
- java.net.URL.equals的调用依赖于网络,每次调用它们的内在可能变化
- 对于非空x: x.equals(null)==false
- 高质量的equals方法
- 使用==检查参数是否为这个对象的引用:if (o == this) return true;
- instance of进行类型检查
- 把参数转化为正确的类型
- 每个关键域检查它们是否匹配
- 非float和double的基本类型直接==比较
- float使用Float.compare比较
- double使用Double.compare比较
- 对于对象引用直接调用equals比较
- 如果是数组域,如果每个元素都是关键域,那么每一个都要比较,jdk1.5后可以通过Arrays.equals解决
- 注意比较顺序带来的性能影响:最易变的先比较
- 写完equals问问:是否对称、传递、一致
- 覆盖equals时总要覆盖hashCode
- 不要企图让equals过于智能
- 不要讲equals中的参数替换为其他类型,这不是覆盖而是重载,所以需要@Override注解
覆盖equals时总要覆盖hashCode
- hashCode 的常规协定是:
- 在 Java 应用程序执行期间,在对同一对象多次调用 hashCode 方法时,必须一致地返回相同的整数,前提是将对象进行 equals 比较时所用的信息没有被修改。从某一应用程序的一次执行到同一应用程序的另一次执行,该整数无需保持一致。
- 如果根据 equals(Object) 方法,两个对象是相等的,那么对这两个对象中的每个对象调用 hashCode 方法都必须生成相同的整数结果。
- 如果根据 equals(java.lang.Object) 方法,两个对象不相等,那么对这两个对象中的任一对象上调用 hashCode 方法不 要求一定生成不同的整数结果。但是,程序员应该意识到,为不相等的对象生成不同整数结果可以提高哈希表的性能。
- hashCode生成简单办法:计算所有的关键域,排除可由其他关键域计算得到的域
- 把非0的常数值保存到result中,如17
- 对于每一个关键域f(equals中涉及的每个域),完成以下步骤:
- 为该域计算int型散列码c:
- boolean return f?1:0
- byte、char、sort或int return f;
-
long return (int)(f^(f>>>32))
- float return Float.floatToIntBits(f)
- double return Double.doubleToLongBits(f)再作为long型来计算散列值
- 引用对象return null?0:f.hasCode();
- 如果是数组,递归处理每一个元素
- 合并result = 31 * result + c
- 为该域计算int型散列码c: