第八条 在改写equals的时候请遵守通用约定

一般以下几种情况,不适宜覆盖equals方法

1.类的每个实例本质上都是唯一的,对于代表活动实体而不是值的类确实如此,例如Thread.

2.不关心类是否提供了“逻辑相等”的测试功能

3.超类已经覆盖了equals,从超类继承过来的行为对子类也是合适的

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

那什么情况应该覆盖Object.equals呢?如果类具有自己特有的“逻辑相等”的概念(不同于对象等同的概念),而且超类没有覆盖equals以实现期望的行为,就需要进行覆盖,这通常属于“值类”的情形,例如Integer和Date。当使用equals来比较对象, 是希望他们在逻辑上是否相等, 而不是指向同一对象, 或者用来作为Map的key以及集合Set中的元素时, 就必须复写equals方法.

实例受控,确保“每个值最多只存在一个对象”的类,枚举通常属于这种类型。对于枚举类型来说, 逻辑相等与对象相等是同一回事, 因此不需要覆盖equals方法。

equals的改写规范:

1)自反性:对于任何非null的引用值x,x.equals(x)一定为true

2)对称性:对于任何非null的引用值x和y,当且仅当x.dquals(y)为true;那么y.equals(x)也必须为true

3)传递性:对于任何非null的引用值x和y和z,如果x.equals(y)为true,y.equals(z);那么x.equals(x)也必须为true

4)一致性:对于任何非null的引用值x和y,如果用于equals比较的对象信息没有被修改的话,那么多次调用x.dquals(y)返回的值是一致的

5)对于非null引用值x,x.equals(null)一定返回false

接下来是逐一解析上面几个原则:

2)对称性

public final class CaseInsensitiveString {
    private final String s;

    public CaseInsensitiveString(String s) {
        if (s == null)
            throw new NullPointerException();
        this.s = s;
    }

    // Broken - violates symmetry!
    @Override
    public boolean equals(Object o) {
        if (o instanceof CaseInsensitiveString)
            return s.equalsIgnoreCase(((CaseInsensitiveString) o).s);
        if (o instanceof String) // One-way interoperability!
            return s.equalsIgnoreCase((String) o);
        return false;
    }

    // This version is correct.
    // @Override public boolean equals(Object o) {
    // return o instanceof CaseInsensitiveString &&
    // ((CaseInsensitiveString) o).s.equalsIgnoreCase(s);
    // }

    public static void main(String[] args) {
        CaseInsensitiveString cis = new CaseInsensitiveString("Polish");
        String s = "polish";
        System.out.println(cis.equals(s) + "  " + s.equals(cis));
    }
}

上面代码中的equals企图和String进行比较操作,假设我们有一个不区分大小的字符串和一个普通的字符串:

  CaseInsensitiveString cis = new CaseInsensitiveString("Test");
        String s = "test";

此时cis.equals(s)会返回true,CaseInsensitiveString 类中做了兼容大小写的处理,但是String 的equals方法是不知道要不区分大小写1的,所以s.equals(cis)会返回false,违反了自反性

假如你把CaseInsensitiveString 放到一个集合中

List<CaseInsensitiveString> list = new ArrayList<>();
        list.add(cis);
        list.contains(s);

list.contains(s)有可能返回true,也可能是false,甚至会抛出RumtimeException

为了解决这个问题,只要企图与String互操作的这段代码从equals去掉即可

@Override
    public boolean equals(Object o) {
        return o instanceof CaseInsensitiveString&&s.equalsIgnoreCase(((CaseInsensitiveString) o).s);

    }

3)传递性:

首先以一个简单不可变的二维整形Point类作为开始

《Effective Java》读书笔记(二)之对于所有对象都通用的方法的更多相关文章

  1. 《Effective Java》第3章 对于所有对象都通用的方法

    第8条:覆盖equals时请遵守通用约定 覆盖equals方法看起来似乎很简单,但是有许多覆盖方式会导致错误,并且后果非常严重.最容易避免这类问题的办法就是不覆盖equals方法,在这种情况下,类的每 ...

  2. 《Effective Java》第2章 对所有对象都通用的方法

    第10条:覆盖equals时,请遵守通用约定 1.使用==来比较两个对象的时候,比较的是两个对象在内存中的地址是否相同(两个引用指向的是否为同一个对象):Object中定义的equals方法也是这样比 ...

  3. Java高效编程之二【对所有对象都通用的方法】

    对于所有对象都通用的方法,即Object类的所有非final方法(equals.hashCode.toString.clone和finalize)都有明确的通用约定,都是为了要被改写(override ...

  4. Effective Java 读书笔记之一 创建和销毁对象

    一.考虑用静态工厂方法代替构造器 这里的静态工厂方法是指类中使用public static 修饰的方法,和设计模式的工厂方法模式没有任何关系.相对于使用共有的构造器来创建对象,静态工厂方法有几大优势: ...

  5. 【Effective Java读书笔记】创建和销毁对象(一):考虑使用静态工厂方法代替构造器

    类可以提供一个静态方法,返回类的一个静态实例,如Boolean包装类的一个获取实例的静态方法 public static Boolean valueOf(boolean b) { return (b ...

  6. [Effective Java 读书笔记] 第三章 对所有对象都通用的方法 第八 ---- 九条

    这一章主要讲解Object类中的方法, Object类是所有类的父类,所以它的方法也称得上是所有对象都通用的方法 第八条 覆盖equals时需要遵守的约定 Object中的equals实现,就是直接对 ...

  7. Effective Java:对于全部对象都通用的方法

    前言: 读这本书第1条规则的时候就感觉到这是一本非常好的书.可以把我们的Java功底提升一个档次,我还是比較推荐的.这里我主要就关于覆盖equals.hashCode和toString方法来做一个笔记 ...

  8. [Effective Java]第三章 对所有对象都通用的方法

    声明:原创作品,转载时请注明文章来自SAP师太技术博客( 博/客/园www.cnblogs.com):www.cnblogs.com/jiangzhengjun,并以超链接形式标明文章原始出处,否则将 ...

  9. Effective java读书笔记

    2015年进步很小,看的书也不是很多,感觉自己都要废了,2016是沉淀的一年,在这一年中要不断学习.看书,努力提升自己 计在16年要看12本书,主要涉及java基础.Spring研究.java并发.J ...

  10. Effective Java读书笔记完结啦

    Effective Java是一本经典的书, 很实用的Java进阶读物, 提供了各个方面的best practices. 最近终于做完了Effective Java的读书笔记, 发布出来与大家共享. ...

随机推荐

  1. 20145303《Java程序设计》实验三实验报告

    20145303<Java程序设计>实验三实验报告 ssh公钥配置及git安装: eclipse中git配置: 队友链接: http://www.cnblogs.com/5321z/p/5 ...

  2. Jquery2 基础核心

    学习要点: 1.代码风格 2.加载模式 3.对象互换 4.多个库之间的冲突 本节简单的介绍一下jQuery 一些核心的问题. 一.代码风格 在jQuery程序中,不管是页面元素的选择.内置的功能函数, ...

  3. Java学习笔记-方法引用

    方法引用(Method Reference) 上一篇中记录了Lambda表达式,其可以创建匿名方法.当Lambda表达式只是调用一个存在的方法时,可以采用方法引用(JDK8具有的特性).如下: pub ...

  4. ArrayBlockingQueue,LinkedBlockingQueue分析

    BlockingQueue接口定义了一种阻塞的FIFO queue,每一个BlockingQueue都有一个容量,让容量满时往BlockingQueue中添加数据时会造成阻塞,当容量为空时取元素操作会 ...

  5. sscanf输入总结

    2017-08-21 15:09:47 writer:pprp sscanf很好用的,一般配合gets()来使用 /* theme: usage of sscanf writer:pprp date: ...

  6. Python学习札记(十四) Function4 递归函数 & Hanoi Tower

    reference:递归函数 Note 1.在函数内部,可以调用其他函数.如果一个函数在内部调用自身本身,这个函数就是递归函数. eg.计算阶乘: #!/usr/bin/env python3 def ...

  7. vector的坑——C++primer练习6.33总结

    说来惭愧,一道简单的对vector递归的题目写了一个多小时,最后还是请教了大神才改出来. 首先贴上原代码: void return_vector(vector<int>::iterator ...

  8. Mybatis-Generator插件的使用与Spring集成Mybatis的配置

    参考:http://blog.51cto.com/zero01/2103687 Mybatis-Generator是一个用于自动生成dao层接口.pojo以及mapper xml的一个Mybatis插 ...

  9. JMeter中响应数据显示乱码问题解决

    方法一.UTF-8 路径:JMeter-->bin-->jmeter.properties 打开之后 #sampleresult.default.encoding=ISO-8859-1 改 ...

  10. WPF:自定义ListBox的选择样式

    首先介绍一种简单地方法:就是通过自定义SystemColors类的参数来自定义WPF ListBox选择颜色的, SystemColors的HighlightBrushKey和HighlightTex ...