一、引用相等性与对象相等性

1. 引用相等性

引用到堆上同一个对象的两个引用是相等的,这就是引用的相等性。

如果想要知道两个引用是否相等,可以使用==来比较变量上的字节组合,如果引用到相同的对象,字节组合也会一样:

if (foo == bar){
// 两个引用都指向同一个对象
}

2. 对象相等性

堆上的两个不同对象在意义上是相同的,这就是对象的相等性。

两个对象相等的条件是它们的hashCode相等,而且调用以另一个对象为参数的equals时返回true:

if (foo.equals(bar) && foo.hashCode() == bar.hashCode()) {
// 两个引用指向同一个对象或者两个对象是相等的
}

我们知道所有的类都继承自Object类,而Object类默认的equals方法是使用==进行比较:

public boolean equals(Object obj) {
return (this == obj);
}

Object类的hashCode函数:

public native int hashCode();

是一个native函数,而且返回值类型是整形;实际上,该native方法将对象在内存中的地址作为哈希码返回,可以保证不同对象的返回值不同。

因此,要比较两个对象的相等性,首先需要重写equals和hashCode方法。

二、equals()与hashCode()的规范与关系

1. equals()方法

JDK中说明了实现equals()方法应该遵守的约定:

1)自反性:x.equals(x)必须返回true。

2)对称性:x.equals(y)与y.equals(x)的返回值必须相等。

3)传递性:x.equals(y)为true,y.equals(z)也为true,那么x.equals(z)必须为true。

4)一致性:如果对象x和y在equals()中使用的信息都没有改变,那么x.equals(y)值始终不变。

5)非null:x不是null,y为null,则x.equals(y)必须为false。

2. hashCode()方法

JDK中对hashCode()方法的作用,以及实现时的注意事项做了说明:

1)hashCode()在哈希表中起作用,如java.util.HashMap。

2)如果对象在equals()中使用的信息都没有改变,那么hashCode()值始终不变。

3)如果两个对象使用equals()方法判断为相等,则hashCode()方法也应该相等。

4)如果两个对象使用equals()方法判断为不相等,则不要求hashCode()也必须不相等;但是开发人员应该认识到,不相等的对象产生不相同的hashCode可以提高哈希表的性能。

3. equals()与hashCode()的关系

通过上面两点我们可以推出结论,如果有两个对象a,b,如果有:

a.equals(b),则a.hashCode() == b.hashCode()为真,即两个值相等的对象,他们的hashCode一定相等

反过来则不一定成立。

实际上在Java中,要证明两个对象值相等,只要a.equals(b)为true就可以了。

三、hashCode的作用

总的来说,hashCode()在哈希表中起作用,如HashSet、HashMap等。

当我们向哈希表(如HashSet、HashMap等)中添加对象object时,首先调用hashCode()方法计算object的哈希码,通过哈希码可以直接定位object在哈希表中的位置(一般是哈希码对哈希表大小取余)。如果该位置没有对象,可以直接将object插入该位置;如果该位置有对象(可能有多个,通过链表实现),则调用equals()方法比较这些对象与object是否相等,如果相等,则不需要保存object;如果不相等,则将该对象加入到链表中。

这也就解释了为什么equals()相等,则hashCode()必须相等。如果两个对象equals()相等,则它们在哈希表(如HashSet、HashMap等)中只应该出现一次;如果hashCode()不相等,那么它们会被散列到哈希表的不同位置,哈希表中出现了不止一次。

实际上,在JVM中,加载的对象在内存中包括三部分:对象头、实例数据、填充。其中,对象头包括指向对象所属类型的指针和MarkWord,而MarkWord中除了包含对象的GC分代年龄信息、加锁状态信息外,还包括了对象的hashcode;对象实例数据是对象真正存储的有效信息;填充部分仅起到占位符的作用, 原因是HotSpot要求对象起始地址必须是8字节的整数倍。

四、参考

1. 《Head First Java(第二版)》

2. 详解equals()方法和hashCode()方法

Java中的对象要怎样才算相等的更多相关文章

  1. Java中的对象池技术

    java中的对象池技术,是为了方便快捷地创建某些对象而出现的,当需要一个对象时,就可以从池中取一个出来(如果池中没有则创建一个),则在需要重复重复创建相等变量时节省了很多时间.对象池其实也就是一个内存 ...

  2. 【Java基础】Java中new对象的过程

    序言 联系我上次写的关于Java内存的文章,对象访问在 Java 语言中无处不在,是最普通的程序行为,但即使是最简单的访问,也会却涉及 Java 栈.Java 堆.方法区这三个最重要内存区域之间的关联 ...

  3. 浅谈Java中的对象和引用

    浅谈Java中的对象和对象引用 在Java中,有一组名词经常一起出现,它们就是“对象和对象引用”,很多朋友在初学Java的时候可能经常会混淆这2个概念,觉得它们是一回事,事实上则不然.今天我们就来一起 ...

  4. 【译】Java中的对象序列化

    前言 好久没翻译simple java了,睡前来一篇. 译文链接: http://www.programcreek.com/2014/01/java-serialization/ 什么是对象序列化 在 ...

  5. java中直接打印对象

    java中直接打印对象,会调用对象.toString()方法.如果没有重写toString()方法会输出"类名+@+hasCode"值,hasCode是一个十六进制数 //没有重写 ...

  6. 如何使用java中的对象

    使用java中的对象,分2步: 1.创建一个对象: 2.使用对象的属性和方法. 见下面的示例代码: package com.imooc; //1.定义一个类 public class Telphone ...

  7. Java中String对象的不可变性

    首先看一个程序 package reverse; public class Reverse { public static void main(String[] args) { String c1=n ...

  8. JAVA中JavaBean对象之间拷贝的方法

    JAVA中JavaBean对象之间的拷贝通常是用get/set方法,但如果你有两个属性相同的JavaBean或有大部分属性相同的JavaBean,有个更简便的方法,他们之间的拷贝可以通过copyPro ...

  9. Java中计算对象的大小

    一.计算对象大小的方法 Java中如何计算对象的大小呢,找到了4种方法: 1.java.lang.instrument.Instrumentation的getObjectSize方法: 2.BTrac ...

随机推荐

  1. Eclipse的maven工具

    左侧是组件以及组件依赖树(层级结构):右侧是识别出来的所有的组件:  

  2. "废物利用"也抄袭——废旧喷墨打印机和光驱DIY"绘图仪"

    很长时间没有写博客,因为各种各样的事情占去大块时间,只有零碎时间偶尔在CSDN逛逛也偶尔回几个帖子.很久以前就看到一些光驱DIY雕刻机之类的,很是向往,最近这几天得闲就TB了一套Arduino UNO ...

  3. python 多线程要点

    要点整理 多线程 #coding=utf-8 import threading from time import ctime,sleep def music(func): for i in range ...

  4. IT诗词

    年少太轻狂,误入IT行.白发森森立,两眼直茫茫.语言数十种,无一称擅长.三十而立时,无房单身郎. 年少不经事,埋头编程忙. 指键铿锵落,不及细思量. bug千百个,comment无一行. 休言敏捷易, ...

  5. Socket通讯介绍

    综上原理,代码的实施的步骤如下: Socket Families(地址簇)的三种类型,这个时候是网络层 socket.AF_UNIX unix本机进程间通信 本机之间的不同进程通讯默认是不可以通讯的, ...

  6. GITBOOK/HEXO TRAVIS GITHUB-PAGES 博客搭建

    简介 这年头要是没有个博客都不好意思给别人说你是程序员,我用XX笔记呀,不行吗?不行,这玩意儿要么不能公开分享,要么公开分享要会员,现在到处都是开源,自己学到了东西都不能分享给需要帮助的人,真是伤心呀 ...

  7. linux 利用nethogs查看某进程的网卡流量

    一.nethogs介绍 分享一个linux 下检测系统进程占用带宽情况的检查.来自github上的开源工具. 它不依赖内核中的模块.当我们的服务器网络异常时,可以通过运行nethogs程序来检测是那个 ...

  8. iframe有哪些缺点?

    iframe会阻塞主页面的Onload事件:   iframe和主页面共享连接池,而浏览器对相同域的连接有限制,所以会影响页面的并行加载.使用iframe之前需要考虑这两个缺点.如果需要使用ifram ...

  9. 浅析ECMP等价路由

    1.ECMP简介 Equal-CostMultipathRouting,等价多路径.即存在多条到达同一个目的地址的相同开销的路径.当设备支持等价路由时,发往该目的 IP 或者目的网段的三层转发流量就可 ...

  10. Mybit错误,提示There is no getter for property named 'tid' in 'class java.lang.String'

    改成 <select id="queryStudentByNum" resultType="student" parameterType="st ...