《Effective Java Third》第三章总结:对于所有对象都通用的方法

本文总结了《Effective Java》第三章的主要内容,包括重写equals方法时应遵循的通用约定,如自反性、对称性、传递性、一致性以及非空性。还讨论了何时及如何重写hashCode方法,以保持equals和hashCode的一致性。此外,强调了始终重写toString方法的重要性,以及谨慎处理clone方法的实现。最后,提出了实现Comparable接口的考量,以提供类的自然排序能力。
摘要由CSDN通过智能技术生成

https://sjsdfg.github.io/effective-java-3rd-chinese

https://github.com/clxering/Effective-Java-3rd-edition-Chinese-English-bilingual/

第三章 对于所有对象都通用的方法

10 重写equals方法时遵守通用约定

因为没有哪个类是孤立存在的。一个类的实例常常被传递给另一个类的实例。许多类,包括所有的集合类,都依赖于传递给它们遵守 equals 约定的对象,所以要遵守规定

满足以下任一下条件,则不覆盖 equals 方法:

  • 每个类的实例都是固有唯一的。
    如对于像 Thread 这样代表活动实体而不是值的类来说,这是正确的。
    Object 提供的 equals 实现对这些类来说完全是正确的行为。
  • 类不需要提供一个「逻辑相等(logical equality)」的测试功能。
    例如 java.util.regex.Pattern 可以重写 equals 方法检查两个是否代表完全相同的正则表达式 Pattern 实例,但是设计者并不认为客户需要或希望使用此功能。
    在这种情况下,从 Object 继承的 equals 实现是最合适的。
  • 父类已经重写了 equals 方法,且父类行为完全适合于该子类。
    例如,大多数 Set 从 AbstractSet 继承了 equals 实现、List 从 AbstractList 继承了 equals 实现,Map 从 AbstractMap 的 Map 继承了 equals 实现。
  • 类是私有的或包级私有的,可以确定它的 equals 方法永远不会被调用。
    如果非常厌恶风险,可以重写 equals 方法,抛出异常,以确保不会被意外调用:
@Override 
public boolean equals(Object o) {
   
    throw new AssertionError(); // Method is never called
}

什么时候需要重写:
当一个类具有逻辑相等的概念时(不同于对象本身相同的概念),而超类还没有重写equals;
这通常是“值类(value class)”的情况。
值类指的是只表示值的类,例如Integer或String。程序员在利用equals方法来比较对象的引用时,希望知道它们在逻辑上是否相等,而不是像了解它们是否引用了相同的对象;
为了满足程序猿的需求,不仅必须重写equals方法,而且这样做也使得这个类的实例可以被用作映射表(map)的键(key),或者集合(set)的元素,使映射或者集合表现出预期的行为。

不需要重写的值类:
一种是使用实例控制(instance control)(第 1 )的类,以确保每个值至多存在一个对象;
枚举类型(第 34 )属于这个类别。;
对于这些类,逻辑相等与对象标识是一样的,因此对象的 equals 方法函数与逻辑 equals 方法相同

当你重写 equals 方法时,必须遵守它的通用约定。Object 的规范如下: equals 方法实现了一个等价关系(equivalence relation)。它有以下这些属性:

  • 自反性: 对于任何非空引用 x,x.equals(x) 必须返回 true。

如果你违反了它,然后把类的实例添加到一个集合中,那么 contains 方法可能会说集合中没有包含刚添加的实例

  • 对称性: 对于任何非空引用 x 和 y,如果且仅当 y.equals(x) 返回 true 时 x.equals(y) 必须返回 true。

错误的例子:实现了不区分大小写的字符串的类,但是却与String进行equals相比:

CaseInsensitiveString cis = new CaseInsensitiveString("Polish");
String s = "polish";

System.out.println(cis.equals(s)); // true
System.out.println(s.equals(cis)); // false

解决方案:删除 equals 方法中与 String 类相互操作的恶意尝试,即如果cis.equals传入的参数如果是String类型,则直接返回false

  • 传递性: 对于任何非空引用 x、y、z,如果 x.equals(y) 返回 true,y.equals(z) 返回 true,则 x.equals(z) 必须返回 true。

可以通过组合来代替继承,即在不违反 equals 约定的情况下将值组件添加到抽象类的子类中:

public class ColorPoint {
   
    private final Point point;//组合进Point而不是继承
    private final Color color;//值组件

    public ColorPoint(int x, int y, Color color) {
   
        point = new Point(x, y);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值