《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的读书笔记, 发布出来与大家共享. ...
随机推荐
- 20145314郑凯杰 《Java程序设计》第6周学习总结
20145314郑凯杰 <Java程序设计>第6周学习总结 教材学习内容总结 本次就不放上每个程序的运行结果了,在下面的问题探究里会写出的.代码托管如下: 第十章 InputStream与 ...
- 20145327 《Java程序设计》第二周学习总结
20145327 <Java程序设计>第二周学习总结 教材学习内容总结 JAVA类型:基本类型与类类型(也称参考类型). 基本类型分为:整数(short,int,long).字节(byte ...
- 20144303 《Java程序设计》第七周学习总结
20144303 <Java程序设计>第七周学习总结 教材学习内容总结 第十二章 Lambda Lambda表达式中this的参考对象以及toString()的接受者,是来自Lambda的 ...
- Commons Configuration之一简介
转载自(https://my.oschina.net/u/2000201/blog/486327) 1 简介 Commons Configuration软件类库提供通用配置接口,使Java应用程 ...
- maven项目引入本地包,不使用中央仓库
1. dependendy引入 <dependency> <groupId>com.taobao</groupId> <artifactId>taoba ...
- MySQL中表复制:create table like 与 create table as select
1 CREATE TABLE A LIKE B此种方式在将表B复制到A时候会将表B完整的字段结构和索引复制到表A中来. 2. CREATE TABLE A AS SELECT * FROM ...
- harbor 管理Helm Chart包
官方网站:https://github.com/goharbor/harbor官方用户手册:https://github.com/goharbor/harbor/blob/master/docs/us ...
- 在Extjs 的 TabPanel在 title标题栏上加按扭button
如何在tabPanel的 标题栏的右侧添加操作按扭,效果如图,我总结了两种实现的方案: 第一种方案: 使用tabPanel的tabPbar: Ext.define("CisApp.view. ...
- MySQL索引最左原则
通过实例理解单列索引.多列索引以及最左前缀原则 实例:现在我们想查出满足以下条件的用户id: 因为我们不想扫描整表,故考虑用索引. 单列索引: ALTER TABLE people ADD INDEX ...
- 使用lock锁或Monitor.Enter的目的
锁定的目的:由于多个线程 并行/并发 处理同一个“数据对象”(比如:在其它线程的某个地方发生了Clear.Add.Remove.Change等操作),导致“数据对象”不断变化,没法用了,所以,为了保证 ...