病毒加速了AR、MR和IoT技术的采用
|
再次执行程序,我们会发现此时 equals 返回 true ,这才是我们想要的。 因此,当我们使用自定义对象时。如果需要让两个对象的内容相同时,equals 返回 true,则需要重写 equals 方法。 为什么要重写 equals 和 hashCode ? 在上边的案例中,其实我们已经说明了为什么要去重写 equals 。因为,在对象内容相同的情况下,我们需要让对象相等。因此,不能用 Object 类的默认实现,只去比较内存地址,这样是不合理的。 那 hashCode 为什么要重写呢?这就涉及到集合,如 Map 和 Set (底层其实也是 Map)了。
我们以 HashMap JDK1.8的源码来看,如 put 方法。 左边一列就是一些关键码(key),通过哈希函数,它们都会得到一个固定的值,分别对应右边一列的某个值。右边的这一列就可以认为是一张哈希表。 而且,我们会发现,有可能有些 key 不同,但是它们对应的哈希值却是一样的,例如 aa,bb 都指向 1001 。但是,一定不会出现同一个 key 指向不同的值。 这也非常好理解,因为哈希表就是用来查找 key 的哈希地址的。在 key 确定的情况下,通过哈希函数计算出来的 哈希地址,一定也是确定的。如图中的 cc 已经确定在 1002 位置了,那么就不可能再占据 1003 位置。 思考一下,如果有另外一个元素 ee 来了,它的哈希地址也落在 1002 位置,怎么办呢? hashCode 有什么用? 其实,上图就已经可以说明一些问题了。我们通过一个 key 计算出它的 hashCode 值,就可以唯一确定它在哈希表中的位置。这样,在查询时,就可以直接定位到当前元素,提高查询效率。 现在我们假设有这样一个场景。我们需要在内存中的一块儿区域存放 10000 个不同的元素(以aa,bb,cc,dd 等为例)。那怎么实现不同的元素插入,相同的元素覆盖呢? 我们最容易想到的方法就是,每当存一个新元素时,就遍历一遍已经存在的元素,看有没有相同的。这样虽然也是可以实现的,但是,如果已经存在了 9000 个元素,你就需要去遍历一下这 9000 个元素。很明显,这样的效率是非常低下的。 我们转换一种思路,还是以上图为例。若来了一个新元素 ff,首先去计算它的 hashCode 值,得出为 1003 。发现此处还没有元素,则直接把这个新元素 ff 放到此位置。 然后,ee 来了,通过计算哈希值得到 1002 。此时,发现 1002 位置已经存在一个元素了。那么,通过 equals 方法比较它们是否相等,发现只有一个 dd 元素,很明显和 ee 不相等。那么,就把 ee 元素放到 dd 元素的后边(可以用链表形式存放)。 我们会发现,当有新元素来的时候,先去计算它们的哈希值,再去确定存放的位置,这样就可以减少比较的次数。如 ff 不需要比较, ee 只需要和 dd 比较一次。 当元素越来越多的时候,新元素也只需要和当前哈希值相同的位置上,已经存在的元素进行比较。而不需要和其他哈希值不同的位置上的元素进行比较。这样就大大减少了元素的比较次数。 图中为了方便,画的哈希表比较小。现在假设,这个哈希表非常的大,例如有这么非常多个位置,从 1001 ~ 9999。那么,新元素插入的时候,有很大概率会插入到一个还没有元素存在的位置上,这样就不需要比较了,效率非常高。但是,我们会发现这样也有一个弊端,就是哈希表所占的内存空间就会变大。因此,这是一个权衡的过程。 有心的同学可能已经发现了。我去,上边的这个做法好熟悉啊。没错,它就是大名鼎鼎的 HashMap 底层实现的思想。对 HashMap 还不了解的,赶紧看这篇文章理一下思路:HashMap 底层实现原理及源码分析 所以,hashCode 有什么用。很明显,提高了查询,插入元素的效率呀。 equals 和 == 有什么区别? 这是万年不变,经久不衰的经典面试题了。让我油然想起,当初为了面试,背诵过的面经了,简直是一把心酸一把泪。现在还能记得这道题的标准答案:equals 比较的是内容, == 比较的是地址。 当时,真的就只是背答案,知其然而不知其所以然。再往下问,为什么要重写 equals ,就懵逼了。
首先,我们应该知道 equals 是定义在所有类的父类 Object 中的。 (编辑:阳江站长网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |

