EffectiveJava之对所有对象都通用的方法

377次阅读  |  发布于1年以前

小伙伴们好呀, 今天来和大家分享下 《Effective Java》这本书的 第3章 —— 对所有对象都通用的方法

对所有对象都通用的方法

这个让我想起了刚毕业找工作时,有人问到:“ Object 中有哪些方法?” 哈哈

这一节作者主要说了 equalshashcodetoStringclone和 Comparable 接口 这五个点。

equals 主要说了它的特点:自反性对称性传递性一致性非空性

不过这些规则 IDEA 都实现了,包括 hascode,这里就不多赘述了。

equals 和 hashcode

关于 equals 和 hashcode ,这里就有一些常见的面试题:

为什么重写 equals() 时必须重写 hashCode() 方法?

首先,已经有了约定:相等的对象必须具有相等的hash code ,不重写就违反了

其次,不重写的话,当我们使用 HashSet,HashMap 之类的集合并将该对象作为 key 时,就会出现这些情况

  1. 添加了两个属性一模一样的对象到这个 set 中
  2. hashMap get equals一样的对象时,却得到 null

所以,我们必须要 重写 这个 hashCode,将对象的所有属性都加到hash算法中,确保相同的对象计算出来的 hascode 是一样的。

为什么要有 hashCode?

hashMap 等容器为了提高执行效率,put 时,会先看 hash 值,再去调用 equals 进行判断,hashCode 方法的开销比 equals 小。

hashCode 相等的两个对象,不一定相等?

hashCode 的产生和我们写的hash算法有关,如果我将某个类的 hashCode 方法重写,并固定返回 1, 那不管创建多少个属性不同的对象,他们的 hashCode 还是一样,但仍然不相等。

hashCode 不相等的,对象一定不相等。

hashCode 和 equals 都相等的,对象一定相等。

常见的重写了 hashCode 的类

小扩展

这里还可以扩展出关于 HashSet, HashMap 的面试题,比如

这里简单回答下:

HashSet 的底层是 HashMap,实际还是调用HashMap 的 put 方法。

put 流程会先计算 hash 值所在 bucket 的 index,碰撞的话调用 equals 判断 key 是否相同,相同就覆盖。不同 key 的话,会判断当前是 链表 还是 红黑树,再进行插入,插入后会考虑是否要扩容(存在的元素 > 集合大小 * 负载因子)

get 流程也是计算 hash 值所在 bucket 的 index,存在的话再通过 equals 判断 key 是否相同,先看看第一个元素是不是,不是的话,再看看是 链表 还是 红黑树,再接着判断。

可以看看之前写的文章

[面试, HashMap,看?]

toString

这个就是方便我们调试代码,把所有属性打印出来。

要注意:两个类相互引用的问题,不然会有 栈溢出 的情况。

clone

这个没用过,重写该方法时,必须实现 Cloneable 接口,不然会抛出 CloneNotSupportedException 异常。

Comparable 接口

比如 Arrays.sort() , TreeSet 等和排序有关的都会用到。

Integer

在之前的这篇文章

[一文带你了解 TreeMap ,LinkedHashMap 的主要特点] 中也有简单提到过

总结

这一章,主要还是讲 hashCodeequals 这两个方法,通过他们,可以对 hash 容器的底层更加了解,以及一些常见的面试点,还有两个对象相等的必要条件:equals 和 hashCode 都要相等,其他的就简单带过了~

Copyright© 2013-2020

All Rights Reserved 京ICP备2023019179号-8