文档章节

《Effective Java》读书笔记——对象的通用方法

b
 belllee
发布于 2017/02/22 20:43
字数 1510
阅读 8
收藏 0

##第8条,覆盖equals时请遵守通用约定# 除非必要,不要重写equals方法。注意:

  • 类的每个实例本质上都是唯一的。这时候继承的Object的euqals方法是完全正确的,不需要重写
  • 不关心类是否提供“逻辑相等”功能。比如Random类。
  • 超类(父类)已经重写了quals,对于子类是适用的,无需重写。例如:AbstractSet——>Set,AbstractList——>List,AbstractMap——>Map
  • 类是私有的或者是包级私有的,并且确定它的equals方法永远不会被调用时。可以进行如下重写,防止意外调用:
    @Override public boolean equals(Object o){
        throw new AssertionError();
    }
  • 如果类具有自己特有的“逻辑相等概念”,而且超类还没有覆盖equals实现期望的行为,此时就需要重写equals方法。重写后被用做map的key,或者set的元素时才能表现出预期的行为。
  • 对于“每个值至多只存在一个对象”的“值类”,Object的euqals方法等同于逻辑相等。例如:枚举类型 Object的euqals方法的规范:
  • 自反性(reflexive)。对于任何非null的引用值x,x.equals(x)必须返回true。
  • 对称性(symmetric)。对于任何非null的引用值x和y,当且仅当y.equals(x)返回true时,x.equals(y)必须返回true。
  • 传递性(transitive)。对于任何非null的引用值x、y和z,如果x.equals(y)返回true,并且y.equals(z)也返回true,那么x.equals(z)必须返回true。
  • 一致性(consistent)。对于任何非null的引用值x和y,只要x,y没有被修改过,多次调用x.equals(y),返回值一定是一致的。
  • 对于任何非null的引用值x,x.equals(null)必须返回false。 如果不符合这些规范,程序会表现异常,甚至是崩溃,而且很难找到根源。 在子类和超类,子类之间,以及同一个超类的子类之间,equals就很有可能出现问题。我们无法在扩展可实例化的类的同时,既增加新的值组件,同时又保留equals约定。推荐用复合的方式代替继承,每个属性分别equals。
    public class ColorPoint {
		 private Point point;
		 private Color color;
		 @Override public boolean equals(Object o){
			 if(!(o instanceof ColorPoint)){
				 return false;
			 }
			 ColorPoint cp = (ColorPoint)o;
			 return cp.point.equals(point) && cp.color.equals(color);
		 }
	 }

equals实现时一般要使用instanceof进行类型检查,对null检查时必定返回false,所以没必要再检查是否为null。 实现高质量equals方法的诀窍:

  • 使用==操作符检查“参数是否为这个对象的引用”。(出于性能优化方面考虑)
  • 使用instanceof操作符检查“参数是否为正确的类型”。所谓“正确的类型”一般是指类,如果接口改进了equals约定,允许实现该接口的类之间进行比较,就可以使用接口。例如Set、List、Map和Map.Entry。
  • 把参数转换成正确的类型。即转换成当前对象的类型。
  • 对该类中的每个关键域(属性),分别进行比较。除float和double的基本值类型,直接使用==比较。float使用Float.compare,double使用Double.compare。如果要检查数组中的每个元素,可以使用Arrays.equals。对于引用域,可能存在null为合法值,需要进行null检查。多个域的情况下,要优先比较开销低的域。
  • 要确保equals符合对称性,传递性和一致性。
  • 不要企图让equals做过多的比较
  • 不要将equals方法的参数类型必须是Object,不能改成当前类。因为没有重写Object.equals,只是重载了。

##第9条:重写equals时必须重写hashCode# 如果没有重写hashCode方法,就无法作为散列集合(例如:HashMap,HashSet和HashTable)的key。因为在取值时会优先通过hashCode比较。

##第10条,始终要重写toString# toString在打印日志时,可以明确当前实例的重要信息,便于理解。而且要注意格式一旦确定就不要修改,格式要便于字符串解析,去除对应域的值。

##第11条,谨慎的重写clone# 如果要支持clone需要实现Cloneable接口。 clone方法就是一个构造器,你必须确保它不会伤害到原始的对象,并确保正确地创建被克隆对象中的约束条件。

  • 对于子类型的域直接使用Object.clone即可。
  • 对于可变的引用类型,可变引用类型的集合,就需要递归的调用clone。以避免伤害到原始对象。
    @Override public Stack clone() {
		 try{
			 Stack result = (Stack) super.clone();
			 result.date = date.clone();
			 result.elements = elements.clone();
             return result;
		 } catch (CloneNotSupportedException e) {
			 throw new AssertionError();
		 }
	 }
  • clone架构与引用可变对象的final域的正常用法是不相兼容的,除非在clone对象和原始对象间可以安全的共享此可变对象。
  • 对于散列桶数组,需要遍历每个数据元素,进行深度拷贝进行clone。
  • clone不应该在构造的过程中,调用新对象中任何非final的方法,防止新旧对象不一致。
  • 对于有线程安全要求的类,clone方法要处理好同步。Object.clone没有同步。
  • 对于ID或者时间戳一类的值域,注意clone后进行修正。
  • 可以考虑使用拷贝构造器或者拷贝工厂方法,更加灵活的实现拷贝操作,比如带参数或者类型转换(比如用数组生成List对象)。
  • 如果不能提供良好保护的clone方法,他的子类就不可能实现Cloneable接口。

编程通则:永远不要让客户去做任何类库能够替客户完成的事情。 ##第12条,考虑实现Compareable接口# compareTo的通用约定与equals类似。 注意:HashSet实例中添加new BigDecimal("1.0")和new BigDecimal("1.00"),这个集合将含有两个元素。而如果把类型HashSet改成TreeSet,则只有一个元素。因为HashSet使用equals比较,TreeSet使用comapreTo比较。

© 著作权归作者所有

共有 人打赏支持
b
粉丝 0
博文 80
码字总数 14299
作品 0
浦东
程序员
读书笔记之《Java并发编程的艺术》-并发编程基础

读书笔记部分内容来源书出版书,版权归本书作者,如有错误,请指正。 欢迎star、fork,读书笔记系列会同步更新 git https://github.com/xuminwlt/j360-jdk module j360-jdk-thread/me.j360....

Hi徐敏
2015/11/11
0
8
读书笔记之《Java并发编程的艺术》-线程池和Executor的子孙们

读书笔记部分内容来源书出版书,版权归本书作者,如有错误,请指正。 欢迎star、fork,读书笔记系列会同步更新 git https://github.com/xuminwlt/j360-jdk module j360-jdk-thread/me.j360....

Hi徐敏
2015/11/11
0
1
Spring实战读书笔记(1)

Spring的根本使命是? 简化Java开发 为了降低Java开发的复杂性,Spring采取了哪4种关键策略? 1、基于POJO的轻量级和最小侵入性编程 2、通过依赖注入和面向接口实现松耦合 3、基于切面和惯例...

祥林会跟你远走高飞
2014/12/30
0
0
Android--面试中遇到的问题总结(三)

《Android 开发工程师面试指南 LearningNotes 》,作者是陶程,由梁观全贡献部分。大家可以去知乎关注这两位用心的少年。这份指南包含了大部分Android开发的基础、进阶知识,不仅可以帮助准备...

sealin
2017/02/22
0
0
读书笔记之《Java并发编程的艺术》-并发编程容器和框架(重要)

读书笔记部分内容来源书出版书,版权归本书作者,如有错误,请指正。 欢迎star、fork,读书笔记系列会同步更新 git https://github.com/xuminwlt/j360-jdk module j360-jdk-thread/me.j360....

Hi徐敏
2015/11/11
0
1

没有更多内容

加载失败,请刷新页面

加载更多

Nginx 配置url 跳转

Step 1:前言 公司一个管理后台,每次访问要写很长的参数,想直接访问域名就去管理页面 Step 2:配置 location / { rewrite ^/$ http://pay-admin.sasha-lab.com/index.php?m=admin&c...

Linux_Anna
21分钟前
2
0
php7在FreeBSD系统下静态编译iconv,导致BUS ERROR (core dump)解决

bug页面: https://bugs.php.net/bug.php?id=72198 触发此bug需要很多条件: FreeBSD系统(10.0以上),Linux系统、MacOS下均无此问题 静态编译iconv扩展,动态iconv扩展也无此问题 系统安装了...

hell0cat
24分钟前
3
0
FireFox下载时文件名乱码问题解决

String filename = java.net.URLEncoder.encode(file.getName(), "UTF-8"); response.setHeader("Content-Disposition", "attachment;filename*=utf-8'zh_cn'" + filename);......

放飞E梦想O
32分钟前
1
0
Spring声明式事务不回滚问题

注解 @Transactional 声明事务 内部调用方法不会走代理方式调用,而是类内部的函数调用,有事务注解也不会开启事务 但是当A有事务调用B时,B会加入A事务中,使之为同一事务 A无事务 ,B有事务...

职业搬砖20年
33分钟前
2
0
高并发的“大杀器”:异步化、并行化

高并发的大杀器:异步化 同步和异步,阻塞和非阻塞 同步和异步,阻塞和非阻塞,这几个词已经是老生常谈,但是还是有很多同学分不清楚,以为同步肯定就是阻塞,异步肯定就是非阻塞,其实他们并...

微笑向暖wx
34分钟前
2
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部