第八条:覆盖equals时请遵守通用约定

什么时候需要覆盖equals方法?类具有自己的逻辑相等概念,并且父类的equals方法不能满足需要。
重写equals时需要遵循一下约定:

  • 自反性:非null x,x.equals(x)必须是true
  • 对称性:非null x和y,y.equals(x)和x.equals(y)的结果必须一致
  • 传递性:非null x、y、z,如果x.equals(y)和x.equals(z)的结果为true,那么y.equals(z)也必须为true
  • 一致性:非null x、y,只要equals的比较操作在对象中所用的信息没有被修改,多次调用x.equals(y)的结果就一致。
  • 对于非null x,x.equals(null)一定是false

自反性:不知道怎么写能让这个返回false,如果返回false了,那么把结果添加到Collection集合类中时,那么contains方法就会一直返回false
对称性:

class Fifth1 {
private String s; public Fifth1(String s) {
this.s = s;
} @Override
public boolean equals(Object o) {
if (o instanceof Fifth1) {
return s.equalsIgnoreCase(((Fifth1) o).s);
}
if (o instanceof String) {
return s.equalsIgnoreCase((String) o);
}
return false;
}
}
    Fifth1 fifth1 = new Fifth1("FZK");
String s = "fzk";

这两个比较就违反了自反性,fifth1.equals(s)调用自定义的equals方法,s.equals(fifth1)调用String的equals方法。

    List<Fifth1> list = new ArrayList<Fifth1>();
list.add(fifth1);
list.contains(s);

然后又有这种代码,结果可能是true,也可能抛运行时异常。
传递性:

class Point {
private final int x;
private final int y; public Point(int x, int y) {
this.x = x;
this.y = y;
} @Override
public boolean equals(Object obj) {
if (!(obj instanceof Point))
return false;
Point p = (Point) obj;
return p.x == x && p.y == y;
}
} class ColorPoint extends Point {
private final String color; public ColorPoint(int x, int y, String color) {
super(x, y);
this.color = color;
} }

ColorPoint肯定需要一个equals。

  @Override
public boolean equals(Object obj) {
if (obj instanceof ColorPoint) {
return false;
}
return super.equals(obj) && ((ColorPoint)obj).color.equals(color);
}
    Point p = new Point(1, 1);
ColorPoint colorPoint = new ColorPoint(1, 1, "red");

这两个比较会失去对称性。
这么写equals:

  @Override
public boolean equals(Object obj) {
if (obj instanceof ColorPoint) {
return false;
}
if (!(obj instanceof ColorPoint)) {
return obj.equals(this);
}
// obj is a ColorPoint
return super.equals(obj) && ((ColorPoint)obj).color.equals(color);
}

Point p = new Point(1, 1);
ColorPoint colorPoint1 = new ColorPoint(1, 1, "red");
ColorPoint colorPoint2 = new ColorPoint(1, 1, "blue");
colorPoint1.equals(p);
colorPoint2.equals(p);
colorPoint1.equals(colorPoint2);

比较这三个的时候又会失去传递性。
其实上面的那种设计,没有什么特别好的办法。改变设计框架还能解决上面的问题,第一中办法是将Color作为ColorPoint的成员。另一种办法是将超类建成抽象类,只要不能直接实例花超类的实例,上面的问题就不会发生。

一致性:相等的永远相等,除非改变了什么。在比较的时候,不要使equals依赖不可靠的资源。

非空性:书的作者起的名,指所有的对象和null 比较的时候都不能返回true。还有在方法里不能返回NullpointerException。
在写完一个equals方法时一定要考虑是否是对称的,传递的,一致的。自反和非空通常会自动满足。

忠告:

  • 覆盖equals时也要覆盖hashCode()方法。
  • 不要企图让equals过于智能,会出现很多麻烦的东西
  • 不要将生命的Object替换成其他的东西。如果是其他的就是重载而不是覆盖。

第九条:覆盖equals时总要覆盖hashCode方法

如果覆盖了equals而没有覆盖hashCode,会违反Object.hashCode的通用约定,导致该类无法结合所有基于散列的集合一起正常运作,这样的集合包括HashMap,HashSet,HashTable。

Object规范:

  • 在应用的执行期间,只要对象的equals方法的比较所用到的信息没有被修改,那么对这个同一对象调用多次,hashCode方法都返回同一个正数。在同一个应用程序的多次执行过程中,每次执行所返回的正数可以不一致
  • 如果两个对象根据equals比较相等,那么hashCode放回的整数一定相等
  • 如果两个对象根据equals比较不相等,那么hashCode放回的整数有可能相等。但是应该知道,不同对象返回hashCode不相等会提高散列表的性能。

第十条:始终要覆盖toString方法

第十一条:谨慎地覆盖clone

地十二条:考虑实现Comparable

书中太啰嗦,感觉没什么好说的。

Effective java -- 2 对于所有对象都通用到方法的更多相关文章

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

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

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

    本节主要涉及Object中通用的一些方法,比如equals,hashCode,toString,clone,finalize等等 覆盖equals时请遵守通用约定 equals方法实现的等价关系: 自 ...

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

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

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

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

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

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

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

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

  7. Effective Java读书笔记——第三章 对于全部对象都通用的方法

    第8条:覆盖equals时请遵守通用的约定 设计Object类的目的就是用来覆盖的,它全部的非final方法都是用来被覆盖的(equals.hashcode.clone.finalize)都有通用约定 ...

  8. [Java读书笔记] Effective Java(Third Edition) 第 3 章 对于所有对象都通用的方法

    第 10 条:覆盖equals时请遵守通用约定 在不覆盖equals方法下,类的每个实例都只与它自身相等. 类的每个实例本质上都是唯一的. 类不需要提供一个”逻辑相等(logical equality ...

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

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

随机推荐

  1. 12C 连接方式和 Oracle Easy Connect Naming method

    1.12C 连接方式 PDB is not an instance, so using SID in the connection string will not work. When the dat ...

  2. 【学生成绩管理系统】 大二c语言作业

    几年前写的了,只能在命令行窗口运行,虽然比较挫,还是有一定参考价值... #include <cstdio> #include <conio.h> #include <i ...

  3. Copy-->Mutable Copy

    一.深拷贝和浅拷贝 深拷贝:对象拷贝 - 直接拷贝内容. 浅拷贝:指针拷贝 - 将指针中的地址值拷贝一份. 二.对于 Copy 与 mutableCopy 的实践 思路:我用四个方案来验证 Copy ...

  4. zencart 具体页面调用规则: $body_code变量解析

    zencart $body_code变量解析 修改centerColumn 可以修改中间产品方框的大小 2.2.5 .BODY文件在这个文件生效 require($body_code) include ...

  5. JS——基础知识

    1.alert语句 弹出一个对话框. 2.console 这个是在浏览器的控制台打印输出,也有一些公司将招聘信息打印到浏览器的console窗口,比如百度首页. 3.typeof 用这个关键字可以测试 ...

  6. JavaScript 逗号表达式

    逗号表达式的一般形式是:表达式1,表达式2,表达式3……表达式n  逗号表达式的求解过程是:先计算表达式1的值,再计算表达式2的值,……一直计算到表达式n的值.最后整个逗号表达式的值是表达式n的值.  ...

  7. jQuery + json 实现省市区三级联动

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  8. java中堆和堆栈的区别

    java中堆和堆栈的区别(一) 1.栈(stack)与堆(heap)都是Java用来在Ram中存放数据的地方.与C++不同,Java自动管理栈和堆,程序员不能直接地设置栈或堆. 2. 栈的优势是,存取 ...

  9. HTML5绘制矩形和圆形并且还有获取在这个图层内的坐标的思路和代码 - feilong_12的专栏 - 博客频道 - CSDN.NET

    body{ font-family: "Microsoft YaHei UI","Microsoft YaHei",SimSun,"Segoe UI& ...

  10. svn第一篇----入门指南

    摘要:trunk存放的是主代码,不修改,branch,tag,milestone均是从trunk中衍生的.branch复制trunk中代码用于开发,tag用于存放比较重要的发行版,存放release版 ...