文档章节

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

b
 belllee
发布于 2017/02/22 20:43
字数 1510
阅读 7
收藏 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
Spring实战读书笔记(1)

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

祥林会跟你远走高飞
2014/12/30
0
0
Java语言编程学习之Lambda表达式设计和架构的原则[图]

Java语言编程学习之Lambda表达式设计和架构的原则[图]: 大家都知道,Lambda表达式是对Java语言的一点简单改进,在JDK标准类库中,运行它的方式各种各样。但是大多数的Java代码都不是由开发J...

原创小博客
07/17
0
0
字符串连接你用+还是用StringBuilder

前言 据我所知字符串确实已经成为 Java 开发人员最常用的类了,而且是大量使用。我们都知道,String 其实是封装了字符,所以俩字符串连接就是将字符串对象里面的字符连起来。很多人习惯使用来...

超人汪小建
06/21
0
0
从Java到JVM到OS线程的优先级

前言 Java 的线程的调度机制由 JVM 实现,假如有若干条线程,你想让某些线程拥有更长的执行时间,或某些线程分配少点执行时间,这时就涉及“线程优先级”。 优先级别 Java 把线程优先级分成1...

超人汪小建
06/25
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

OSChina 周日乱弹 —— 种族不同,禁止交往

Osc乱弹歌单(2018)请戳(这里) 【今日歌曲】 @小小编辑:推荐歌曲《苏菲小姐》- 鱼果 《苏菲小姐》- 鱼果 手机党少年们想听歌,请使劲儿戳(这里) @貓夏:下大雨 正是睡觉的好时候 临睡前...

小小编辑
今天
199
6
Python 搭建简单服务器

Python动态服务器网页(需要使用WSGI接口),基本实现步骤如下: 1.等待客户端的链接,服务器会收到一个http协议的请求数据报 2.利用正则表达式对这个请求数据报进行解析(请求方式、提取出文...

代码打碟手
今天
1
0
Confluence 6 删除垃圾内容

属性(profile)垃圾 属性垃圾的定义为,一个垃圾用户在 Confluence 创建了用户,但是这个用户在自己的属性页面中添加了垃圾 URL。 如果你有很多垃圾用户在你的系统中创建了属性,你可以使用...

honeymose
今天
0
0
qduoj~前端~二次开发~打包docker镜像并上传到阿里云容器镜像仓库

上一篇文章https://my.oschina.net/finchxu/blog/1930017记录了怎么在本地修改前端,现在我要把我的修改添加到部署到本地的前端的docker容器中,然后打包这个容器成为一个本地镜像,然后把这...

虚拟世界的懒猫
今天
1
0
UML中 的各种符号含义

Class Notation A class notation consists of three parts: Class Name The name of the class appears in the first partition. Class Attributes Attributes are shown in the second par......

hutaishi
今天
1
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部