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 ...
随机推荐
- ICPC Central Russia Regional Contest (CRRC 19)题解
题目连接:https://codeforces.com/gym/102780 寒假第二次训练赛,(某菜依旧是4个小时后咕咕咕),战况还行,个人表现极差(高级演员) A:Green tea 暴力枚举即可 ...
- 浅谈.NET技术公司的实习生培养
浅谈.NET技术公司的实习生培养 背景 近几年.NET开发者市场的越发不景气,一毕业就选择.NET技术的开发者更是少之又少.一方面是公司效益的日益提高,一方面却是招聘优秀人才的速度总是赶不上公司发展的 ...
- 【Java基础】Java8 新特性
Java8 新特性 Lambda 表达式 Lambda 是一个匿名函数,我们可以把 Lambda 表达式理解为是一段可以传递的代码(将代码像数据一样进行传递).使用它可以写出更简洁.更灵活的代码. L ...
- SpringBoot入门 简单搭建和使用
前言 差不多两年前,那个时候我准备要做毕业设计了,才第一次知道java有框架这种东西,在网上找了好多SSM的教程,那会儿真的是Spring+SpringMVC+MyBatis搭建的,印象极深的是还要写 ...
- Rabbitmq可靠消息投递,消息确认机制
前言 我们知道,消息从发送到签收的整个过程是 Producer-->Broker/Exchange-->Broker/Queue-->Consumer,因此如果只是要保证消息的可靠投 ...
- 【RAC】安装cluster软件 在节点2执行root.sh脚本
安装cluster软件 在节点2执行root.sh脚本 报错如下: Running vipca(silent) for configuring nodeapps /db/oracle/product ...
- JDK的各个版本
Java的各个版本 从上图我们看出,Java的版本名最开始以JDK开头,后来以j2se开头,最后到现在以Java开头,所以这些名字我们都可以说,但人们说的更多的是JDK多少,或者Java多少
- 相对论中的光速c不变,这么讲!你总能理解了吧!
今天谈谈相对论的假设基础--光速不变,很多人都知道爱因斯坦的相对论,也知道相对论的理论基础是光速不变,即无论参考哪个参照系,光的速度都是不变的,这个很难得理解的问题.我之前看过别人的理解,也自己思考怎 ...
- 《awk中文手册》-本人参考官方手册翻译
01. 简介 AWK是一个文本(面向行和列)处理工具,同时它也是一门脚本语言. AWK其名称得自于它的创始人 Alfred Aho .Peter Weinberger 和 Brian Kernigha ...
- 2021年官网下载各个版本JDK最全版与官网查阅方法
版本说明 1.安装部署JDK (1)环境 (2)官网下载JDK 由于官网的地址会随着时间的修改而更改修改下载地址,现在讲述下通用的界面操作下载JDK,以后JDK收费更严重,估计就只能下载开源的了. A ...