Effective Java读书笔记--对所有对象都通用的方法
1、覆盖equals请遵守通用规定。
不需要覆写equals的场景:
a.类的每个实例都是唯一的。
b.类不需要提供“逻辑相等”的测试功能。
c.超类已经覆盖了equals的方法。
d.类是私有,or包私有,保证equals方法用不被调用。
覆写场景:有独特的“逻辑相等”。
实现要求:
a.自反,对称,传递,一致(多次比较得一样),对于任何非null值和null比较必须返回false。
一致:不要使equals依赖不可靠的资源。(比如java.net.URL的equals依赖于URL中IP的的比较,IP可能会变。)
对于float,double可以使用Float和Double的compare(float,float),compare(double,double)方法做比较。因为有Float.NaN,-0.0f等。虽然可以用Float.equals(),Double.equals()的静态方法对double和float进行比较,但是自动装箱,导致性能下降。
注意考虑性能:把关键的先决条件放前面比较,比如只要面积不相等,就不需要再比较顶点和角。
b.覆盖equals总是要覆盖hashCode
c.不要试图让equals过于智能。
d.不要将equals声明中的Object对象替换为其他类型。反例:equals(MyClass o);正例:equals(Object o)
2、覆盖equals总要覆盖hashCode
equals相等,hashCode一定要相等。如果equals不相等,hashCode最好不相等。
实现hashCode的方法:
第一个域的hashCode就是本身的hashCode(一般是Type.hashCode(f))
每个域hashCode*31 + 累计的域的hashCode
使用31是因为31是奇素数。如果使用偶数,乘法溢出会导致信息丢失,乘以2等价于移位运算。信息丢失,hash碰撞概率更大。乘的数不宜过大,不宜过小。否则容易碰撞。31应该是个不易碰撞的因子。31有个好特性,可以用移位和减法代替。31*i=(32-1)*i=(32i -i)=(i<<5)-i。
其他hashCode方法:Arrays.hashCode()对数组每个元素hashCode的总的组合。
尽可能不冲突:com.google.common.hash.Hashing[Guava].
不注重性能可以用法Object.hash(Object... o)
不可变类,并且hashCode计算开销大,可以考虑缓存,或者延迟加载。
private int hashCode;
@Override public int hashCode(){
int result = hashCode;
if(result == 0){
//再计算hashCode;
}
return result;
}
不要试图从hashCode计算中排除掉关键领域提高性能,可能会导致hash碰撞更严重。
3、始终要覆盖toString方法
默认toString:类名+@+hashCode无符号16进制整数。
4、谨慎地覆盖clone
Object的clone方法是受保护的(protected),不能直接调用,得由子类去调用,实现Cloneable方法,否则报CloneNotSupportedException。
不可变类永远不要提供克隆办法,因为它只会激发不必要的克隆。
如果对象中包含的域引用了可变的对象(Object的clone方法只会做引用复制),比如数组,对克隆对象的数组改变,会影响原来的对象!!!(深拷贝和浅拷贝的问题)
实际上,clone方法就是另外一个构造器;必须确保它不会伤害到原始的对象,并确保正确地创建被克隆对象的约束条件。
在数组上调用clone返回的数组,其编译时的类型与被克隆数组的类型相同。这是复制数组的最佳习惯。数组是clone方法唯一吸引人的地方。
就像序列化一样,Clonable架构与引用可变对象的final域的正常用法是不相兼容的。
克隆复杂对象最后一种办法是:
先调用super.clone(),然后哉把结果对象中的所有域都设置成初始状态。
公有的clone方法应该省略throws声明,因为不抛出受检异常的方法使用起来更轻松。
为继承而设计的类最好自己实现一个protected的clone方法,里面抛出ClassNotSupportedException
同时有必要的时候,在多线程环境要考虑clone方法线程安全。
对象拷贝的更好办法是提供一个拷贝构造器或者是拷贝工厂。
public Yum(Yum yum){};
public static Yum newInstance(Yum yum){};
最好的办法就是不应该扩展clone这个接口。少数有必要才实现。当然基本类型/不可变类型数组clone是例外。
5、考虑实现Comparable接口
实现Comparable要求:
sgn表示根据表达式的值返回-1,0,1
1、sgn(x.compareTo(y)) = -sgn(y.compareTo(x))
2、传递性
3、如果x.compareTo(y) = 0,则 sgn(x.compareTo(z)) = sgn(y.compareTo(z))
4、最好保证(x.compareTo(y) == 0)= (x.equals(y)),否则最好注释说明
只在同类型之间比较,在不同类型之间就抛出ClassCastException
违反compareTo的约定也会破坏依赖的相关类,比如TreeSet,TreeMap,以及工具类Collections和Arrays。
Collection、Set、Map的通用约定是用equals来做等同性,但是有序集合使用compareTo而不是equals来做等同性。比如HashSet添加new BigDecimal("1.0") 和 new BigDecimal("1.00")是2个元素,
TreeSet是1个元素。
先比较重要字域,再比较次要的。
java 8 开始 Comparator配置了一组比较器构造方法:long,int,double,float等Comparable.comparingInt();
实现compare 不要用+,-之类可能导致整数溢出的情况。避免使用<,>大于小于实现很复杂。多用相关装箱类型中的compare方法,或者Comparator的比较构造器。
Effective Java读书笔记--对所有对象都通用的方法的更多相关文章
- Effective Java 学习笔记之所有对象都通用的方法
一.覆盖equals时请遵守通用约定 1.满足下列任何一个条件时,不需要覆盖equals方法 a.类的每个实例本质上都是唯一的.此时就是Object中equals方法所表达的含义. b.不关心类是否提 ...
- Effective Java2读书笔记-对于所有对象都通用的方法(一)
第8条:覆盖equals时请遵守通用约定 ①约定的内容 自反性.对于任何非null的引用值x.x.equals(x)必须返回true. 对称性.对于任何非null的引用值x和y.当且仅当y.equal ...
- Effective Java2读书笔记-对于所有对象都通用的方法(二)
第10条:始终要覆盖toString 这一条没什么好讲的,就是说默认的toString方法打印出来的是类名+@+十六进制哈希码的值.我们应该覆盖它,使它能够展示出一些更为详细清晰的信息,这个看实际情况 ...
- Effective Java2读书笔记-对于所有对象都通用的方法(三)
第12条:考虑实现Comparable接口 这一条非常简单.就是说,如果类实现了Comparable接口,覆盖comparaTo方法. 就可以使用Arrays.sort(a)对数组a进行排序. 它与e ...
- [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 读书笔记
创建和销毁对象 >考虑用静态工厂方法替代构造器. 优点: ●优势在于有名称. ●不必再每次调用他们的时候都创建一个新的对象. ●可以返回原返回类型的任何子类型的对象. ●在创建参数化类型实例的时 ...
- Java高效编程之二【对所有对象都通用的方法】
对于所有对象都通用的方法,即Object类的所有非final方法(equals.hashCode.toString.clone和finalize)都有明确的通用约定,都是为了要被改写(override ...
随机推荐
- 学习笔记之Python人机交互小项目二:名片管理系统
继上次利用列表相关知识做了简单的人机交互的小项目名字管理系统后,当学习到字典时,老师又让我们结合列表和字典的知识,结合一起做一个名片管理系统,这里分享给在学习Python的伙伴! 1.不使用函数 1 ...
- SpringBoot 集成Elasticsearch进行简单增删改查
一.引入的pom文件 <?xml version="1.0" encoding="UTF-8"?> <project xmlns=" ...
- Head First 设计模式 —— 04. 工厂 (Factory) 模式
思考题 如何将实例化具体类的代码从应用中抽离,或者封装起来,使它们不会干扰应用的其他部分? P111 将实例化具体类的代码放入一个对象中管理,通过不同入参决定实例化具体的类 简单工厂 不是23种GOF ...
- 软件“美不美”,UI测试一下就知道
摘要:软件测试的最高层次需求是:UI测试,也就是这个软件"长得好不好看". 为了让读者更好地理解测试,我们从最基础的概念开始介绍.以一个软件的"轮回"为例,下图 ...
- [Skill] 记一次vue项目热更新失败案例
病因 修改文件后无法更新界面,感觉留白,没有更新 解决过程 发现问题,第一步搜索别人是怎么解决的 搜索一阵后,发现大部分都是留言路径问题,基本都是组件文件夹大写导致 修改测试后发现问题依旧 然后仔细观 ...
- C#:使用连接字符串连接数据库
前言:在上学期选择专业时候,选择的是互联网(还有物联网),这学期相关课程便是使用c#完成一个管理系统:最近的作业是完成一个对数据库操作类,操作数据库?虽然是很简单的一个作业,但也是懵逼了很久,在网上找 ...
- 关于.NET中的控制反转(一)- 概念与定义
一.控制反转 1:类与类的依赖 依赖是面向对象中用来描述类与类之间一种关系的概念.两个相对独立的对象,当一个对象负责构造另一个对象的实例,或者依赖另一个对象的服务,这样的两个对象之间主要体现为依赖关系 ...
- 【剑指 Offer】06.从尾到头打印链表
题目描述 输入一个链表的头节点,从尾到头反过来返回每个节点的值(用数组返回). 示例 1: 输入:head = [1,3,2] 输出:[2,3,1] 限制: 0 <= 链表长度 <= 10 ...
- Session、Cookie与Token
http协议是无状态协议 协议是指计算机通信网络中两台计算机之间进行通信所必须共同遵守的规定或规则,超文本传输协议(HTTP)是一种通信协议,它允许将超文本标记语言(HTML)文档从Web服务器传送到 ...
- 【Python】简单的脚本,轻松批量修改文件名称
使用python脚本,批量修改文件夹名称 先创建一些没用的案例文件 import os #创建新文件夹 dir = os.makedirs('D:\\SomeThing\\testfile') #将文 ...