《Effective Java》读书笔记(二)之对于所有对象都通用的方法
第八条 在改写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》读书笔记(二)之对于所有对象都通用的方法的更多相关文章
- 《Effective Java》第3章 对于所有对象都通用的方法
第8条:覆盖equals时请遵守通用约定 覆盖equals方法看起来似乎很简单,但是有许多覆盖方式会导致错误,并且后果非常严重.最容易避免这类问题的办法就是不覆盖equals方法,在这种情况下,类的每 ...
- 《Effective Java》第2章 对所有对象都通用的方法
第10条:覆盖equals时,请遵守通用约定 1.使用==来比较两个对象的时候,比较的是两个对象在内存中的地址是否相同(两个引用指向的是否为同一个对象):Object中定义的equals方法也是这样比 ...
- Java高效编程之二【对所有对象都通用的方法】
对于所有对象都通用的方法,即Object类的所有非final方法(equals.hashCode.toString.clone和finalize)都有明确的通用约定,都是为了要被改写(override ...
- Effective Java 读书笔记之一 创建和销毁对象
一.考虑用静态工厂方法代替构造器 这里的静态工厂方法是指类中使用public static 修饰的方法,和设计模式的工厂方法模式没有任何关系.相对于使用共有的构造器来创建对象,静态工厂方法有几大优势: ...
- 【Effective Java读书笔记】创建和销毁对象(一):考虑使用静态工厂方法代替构造器
类可以提供一个静态方法,返回类的一个静态实例,如Boolean包装类的一个获取实例的静态方法 public static Boolean valueOf(boolean b) { return (b ...
- [Effective Java 读书笔记] 第三章 对所有对象都通用的方法 第八 ---- 九条
这一章主要讲解Object类中的方法, Object类是所有类的父类,所以它的方法也称得上是所有对象都通用的方法 第八条 覆盖equals时需要遵守的约定 Object中的equals实现,就是直接对 ...
- Effective Java:对于全部对象都通用的方法
前言: 读这本书第1条规则的时候就感觉到这是一本非常好的书.可以把我们的Java功底提升一个档次,我还是比較推荐的.这里我主要就关于覆盖equals.hashCode和toString方法来做一个笔记 ...
- [Effective Java]第三章 对所有对象都通用的方法
声明:原创作品,转载时请注明文章来自SAP师太技术博客( 博/客/园www.cnblogs.com):www.cnblogs.com/jiangzhengjun,并以超链接形式标明文章原始出处,否则将 ...
- Effective java读书笔记
2015年进步很小,看的书也不是很多,感觉自己都要废了,2016是沉淀的一年,在这一年中要不断学习.看书,努力提升自己 计在16年要看12本书,主要涉及java基础.Spring研究.java并发.J ...
- Effective Java读书笔记完结啦
Effective Java是一本经典的书, 很实用的Java进阶读物, 提供了各个方面的best practices. 最近终于做完了Effective Java的读书笔记, 发布出来与大家共享. ...
随机推荐
- wix toolset将 cab 打包进msi
在***wxs中添加配置 <MediaTemplate EmbedCab="yes" /> 下面是一个简单配置:(包含写注册表) <?xml version=&q ...
- 基于tomcat集群做session共享
前端代理服务器nginx:192.168.223.136 tomcat服务器:采用的一台多实例192.168.223.146:8081,192.168.223.146:8082(如何构建多实例tomc ...
- 20145329《Java程序设计》第十周学习总结
教材学习内容总结 网络编程 • 网络编程就是在两个或两个以上的设备(例如计算机)之间传输数据.程序员所作的事情就是把数据发送到指定的位置,或者接收到指定的数据 1.网络概述 • 网络编程的实质:两个( ...
- 20145335郝昊《java程序设计》第8周学习总结
20145335郝昊 <Java程序设计>第8周学习总结 教材学习内容总结 第14章 NIO与NIO2 NIO简介 NIO使用频道来衔接数据结点,在处理数据时,NIO可以让你设定缓冲区容量 ...
- 入手sm961
测速: 发现这个测速软件不同版本测试还不一样 下面是我的intel750的,用最新版本测试软件测的 淘宝买了一个散热片
- tomcat配置根目录访问后,部署后第一次访问会出现tomcat的默认界面而非项目首页
tomcat配置根目录访问后,部署后第一次访问会出现tomcat的默认界面而非项目首页,而重启后会正常,这个原因是因为在配置文件中有如下配置,造成项目加载两次 <Host name=" ...
- HA-web-services
一.HA部署 本次实验的程序选型为heartbeat v1 + hearesources.资源有IP和httpd,filesystem 配置HA集群的前提: (1)各节点资源一致,硬件或软件环境一致 ...
- linux怎么上真正的国际互联网
1.安装git yum install -y git 2.执行git clone git@github.com:XX-net/XX-Net.git 3.升级python到python 2.7(妈妈说p ...
- django教程目录
什么是web框架? Do a web framework ourselves MVC和MTV模式 django的流程和命令行工具 Django的配置文件(settings) Django URL (路 ...
- Eclipse创建Maven聚合项目
整体架构图 1.新建父工程 新建maven父项目(用来管理jar包版本),使子系统使用同一个版本的jar包. File->New->Other->Maven Project,打包方式 ...