JDK1.8 --- Object类的HashCode、equals、clone方法解析

一、public native int hashCode()

       返回当前对象运行时的hash码。(在jdk源码中的解释是用于支持散列表数据结构,因为散列表在进行数据存储时依赖hash码决定数据存储的位置(逻辑位置)。在程序运行中,无论什么情况下,相同的对象对应的hash码一定是相同的。但是不同的对象有可能会返回相同的hash码。那么其实也代表如果两个对象的hash码不一致,这两个对象一定是不同的。)
这里我们做一下延伸:

为什么需要Hash码?
       Hash码的作用:文本校验,数字签名。

hash码到底是什么?(这里我们引用百度百科的内容)
       Hash译作“散列”,就是把任意长度的输入(又叫做预映射pre-image)通过散列算法变换成固定长度的输出,该输出就是散列值。这种转换是一种压缩映射,也就是,散列值的空间通常远小于输入的空间,不同的输入可能会散列成相同的输出,所以不可能从散列值来确定唯一的输入值。简单的说就是一种将任意长度的消息压缩到某一固定长度的消息摘要的函数。

以上有一些概念需要一一作出解释:
常见的散列算法:

  1. 余数法:先估计整个哈希表中的表项目数目大小。然后用这个估计值作为除数去除每个原始值,得到商和余数。用余数作为哈希值。因为这种方法产生冲突的可能性相当大,因此任何搜索算法都应该能够判断冲突是否发生并提出取代算法。
  2. 折叠法:这种方法是针对原始值为数字时使用,将原始值分为若干部分,然后将各部分叠加,得到的最后四个数字(或者取其他位数的数字都可以)来作为哈希值。
  3. 基数转换法:当原始值是数字时,可以将原始值的数制基数转为一个不同的数字。例如,可以将十进制的原始值转为十六进制的哈希值。为了使哈希值的长度相同,可以省略高位数字。
  4. 数据重排法:这种方法只是简单的将原始值中的数据打乱排序。比如可以将第三位到第六位的数字逆序排列,然后利用重排后的数字作为哈希值。

Java中Hashcode方法的规定:

  • 在 Java 应用程序执行期间,在对同一对象多次调用 hashCode 方法时,必须一致地返回相同的整数,前提是将对象进行 equals 比较时所用的信息没有被修改。从某一应用程序的一次执行到同一应用程序的另一次执行,该整数无需保持一致。

  • 如果根据 equals(Object) 方法,两个对象是相等的,那么对这两个对象中的每个对象调用 hashCode 方法都必须生成相同的整数结果。

  • 如果根据 equals(java.lang.Object) 方法,两个对象不相等,那么对这两个对象中的任一对象上调用 hashCode方法不 要求一定生成不同的整数结果。但是,程序员应该意识到,为不相等的对象生成不同整数结果可以提高哈希表的性能。

Hotspot中hashcode方法的实现:


图片 1.png

       hash方法的实现是先获取该对象的标记字对象,然后对该标记字对象的的地址做位移和逻辑与操作,以结果作为hashcode(其中,mark_bits方法在globalDefinitions.hpp),之所以做移位操作是因为hashcode在标记字中只占用了部分位(32位机器上是占用25位,64位机器上占用31)
       从实现来看,我们试图解释hashcode的一个现象,为什么不同的对象可能返回相同的hashcode方法?
因为尽管虚拟机在运行过程中,不同的对象的地址一定是不同的,但是由于hashcode需要固定25位或者31位,那么就导致真正的hashcode值需要在对象地址上做一定的操作。从而将一个大范围区间的值映射到一个小范围区间的值(hashcode的计算过程),这样的操作必定会导致一部分数据的计算结果会重复。所以说这就是不同的对象可能返回相同hash值的原因。

二、 public boolean equals(Object obj)

图片 1.png

在java中equals的作用是,判断两个对象是不是相等的。
       从jdk的实现可以看出:equals其实就是在比较两个对象的地址是否相等,所以这个方法不存在hashcode()的问题,因为对象在内存中的地址是唯一的。
重写equals()方法就必须重写hashCode()方法的原因。
       假设两个对象,重写了其equals方法,其相等条件是属性相等,就返回true。如果不重写hashcode方法,其返回的依然是两个对象的内存地址值,必然不相等。这就出现了equals方法相等,但是hashcode不相等的情况。这不符合hashcode的规则。在集合框架中,这种情况会导致的严重的问题,具体的问题在hashMap中会具体分析。

三、 protected native Object clone()

本地方法表
static JNINativeMethod methods[] = {
       {"hashCode", "()I", (void *)&JVM_IHashCode},
       {"wait", "(J)V", (void *)&JVM_MonitorWait},
       {"notify", "()V", (void *)&JVM_MonitorNotify},
       {"notifyAll", "()V", (void *)&JVM_MonitorNotifyAll},
       {"clone", "()Ljava/lang/Object;", (void *)&JVM_Clone}
};
       由本地方法表知道clone方法对应的本地函数为JVM_Clone,clone方法主要实现对象的克隆功能,根据该对象生成一个相同的新对象(我们常见的类的对象的属性如果是原始类型则会克隆值,但如果是对象则会克隆对象的地址)。Java的类要实现克隆则需要实现Cloneable接口,if (!klass->is_cloneable())这里会校验是否有实现该接口。然后判断是否是数组分两种情况分配内存空间,新对象为new_obj,接着对new_obj进行copy及C++层数据结构的设置。最后再转成jobject类型方便转成Java层的Object类型。
源码:


图片 1.png

看到jvm源码之后我们来分析一下:
       底层在实现clone()方法其实非常简单,一.首先确认当前对象是否实现了cloneable接口(这是一个标记接口),二.分配一个和当前对象一样大小的空间,三.将原对象堆中的区域以字节的方式复制到新对象中。
       然而对象在堆中的存储,对象属性其实存储的只是引用地址,那么使用clone()方法的时候就是我们所说浅拷贝,只是值拷贝。拷贝的接口是拷贝的对象和原对象的对象属性指向同一个地址。对这个属性做改动时,会互相影响。

那么引出一个问题,我们怎么进行深拷贝呢?
       解决的方法是调用对象属性的clone()方法,需要所有的对象属性都重写clone()方法。然后再调用上层对象的clone()方法时,再里面调用属性的对象的clone()方法,实现深拷贝。

还有一个值得思考的问题,String对象如何进行拷贝的?
       String对象本身是个final类,所以在对它做拷贝的时候注定是值拷贝,拷贝之后的String和原来的String指向同一个区域(常量池),然后String有一个基本特性是它的不可变性,如果改变就新增,这样的话虽然是浅拷贝,但变相的实现了深拷贝的效果。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,080评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,422评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,630评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,554评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,662评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,856评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,014评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,752评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,212评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,541评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,687评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,347评论 4 331
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,973评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,777评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,006评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,406评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,576评论 2 349

推荐阅读更多精彩内容