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读书笔记--对所有对象都通用的方法的更多相关文章

  1. Effective Java 学习笔记之所有对象都通用的方法

    一.覆盖equals时请遵守通用约定 1.满足下列任何一个条件时,不需要覆盖equals方法 a.类的每个实例本质上都是唯一的.此时就是Object中equals方法所表达的含义. b.不关心类是否提 ...

  2. Effective Java2读书笔记-对于所有对象都通用的方法(一)

    第8条:覆盖equals时请遵守通用约定 ①约定的内容 自反性.对于任何非null的引用值x.x.equals(x)必须返回true. 对称性.对于任何非null的引用值x和y.当且仅当y.equal ...

  3. Effective Java2读书笔记-对于所有对象都通用的方法(二)

    第10条:始终要覆盖toString 这一条没什么好讲的,就是说默认的toString方法打印出来的是类名+@+十六进制哈希码的值.我们应该覆盖它,使它能够展示出一些更为详细清晰的信息,这个看实际情况 ...

  4. Effective Java2读书笔记-对于所有对象都通用的方法(三)

    第12条:考虑实现Comparable接口 这一条非常简单.就是说,如果类实现了Comparable接口,覆盖comparaTo方法. 就可以使用Arrays.sort(a)对数组a进行排序. 它与e ...

  5. [Effective Java 读书笔记] 第三章 对所有对象都通用的方法 第八 ---- 九条

    这一章主要讲解Object类中的方法, Object类是所有类的父类,所以它的方法也称得上是所有对象都通用的方法 第八条 覆盖equals时需要遵守的约定 Object中的equals实现,就是直接对 ...

  6. Effective Java:对于全部对象都通用的方法

    前言: 读这本书第1条规则的时候就感觉到这是一本非常好的书.可以把我们的Java功底提升一个档次,我还是比較推荐的.这里我主要就关于覆盖equals.hashCode和toString方法来做一个笔记 ...

  7. [Effective Java]第三章 对所有对象都通用的方法

    声明:原创作品,转载时请注明文章来自SAP师太技术博客( 博/客/园www.cnblogs.com):www.cnblogs.com/jiangzhengjun,并以超链接形式标明文章原始出处,否则将 ...

  8. Effective Java 读书笔记

    创建和销毁对象 >考虑用静态工厂方法替代构造器. 优点: ●优势在于有名称. ●不必再每次调用他们的时候都创建一个新的对象. ●可以返回原返回类型的任何子类型的对象. ●在创建参数化类型实例的时 ...

  9. Java高效编程之二【对所有对象都通用的方法】

    对于所有对象都通用的方法,即Object类的所有非final方法(equals.hashCode.toString.clone和finalize)都有明确的通用约定,都是为了要被改写(override ...

随机推荐

  1. python函数----名称空间和作用域

    一 名称空间 名称空间即存放名字与对象映射/绑定关系的地方. 对于x=3,Python会申请内存空间存放对象3,然后将名字x与3的绑定关系存放于名称空间中,del x表示清除该绑定关系. ​在程序执行 ...

  2. 2020DevOps状态报告——平台模型:扩展DevOps的新方法

    平台模型是我们在这个领域看到越来越多的方法,它源于负责产品或服务的端到端交付的产品团队的理念.如果只应用于单一的产品,或者几个产品,它的效果很好. 但如果有数百种产品或服务,把一个产品团队用于这些产品 ...

  3. vue-cli3 创建项目路由缺失问题

    1.在项目中新建一个router.js router.js import Vue from 'vue' import Router from 'vue-router' import Home from ...

  4. 剑指offer 面试题9.1:用两个队列实现栈

    题目描述 使用队列实现栈的下列操作:push(x) -- 元素 x 入栈:pop() -- 移除栈顶元素:top() -- 获取栈顶元素:empty() -- 返回栈是否为空: 编程思想 利用双队列实 ...

  5. N叉树的最大深度-DFS

    再看这道题之前,先来一道类似的简单题. 题目:求二叉树的最大深度 给定一个二叉树,找出其最大深度. 二叉树的深度为根节点到最远叶子节点的最长路径上的节点数. 说明: 叶子节点是指没有子节点的节点. 示 ...

  6. 给mysql选择调度策略

    在gun/linux上,队列调度决定了到块设备的请求实际上发送到底层设置的顺序.默认情况下是cfg(完全公平排队)策略,随意使用的笔记本和台式机使用中个调度策略没有问题,并且有助于防止io饥饿,但是用 ...

  7. python异步回调顺序?是否加锁?

    话不多说,直接上代码: import time from functools import partial from concurrent.futures.process import Process ...

  8. oracle 12C单实例打PSU

    前提: oracle不管打什么样的补丁,readme都是很好的参考资料. Oracle每季度都会更新一个最新的PSU,现在12.1.0.2.0的最新的PSU是Patch 26925311. 由于今天白 ...

  9. Kubernetes 开船记-脚踏两只船:用 master 服务器镜像克隆出新集群

    自从2020年2月23日 园子全站登船 之后,我们一边感叹"不上船不知道,一上船吓一跳" -- kubernetes 比 docker swarm 强大太多,一边有一个杞人忧天的担 ...

  10. 使用gui_upload的总结

    今天使用gui_upload函数将文本文件的内容读取到内表.出现了一个问题,总是程序宕掉,出项的提示是 Type conflict when calling a function module. 原来 ...