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

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. Android JNI访问Java成员

    在 JNI 调用中,不仅仅 Java 可以调用本地方法,本地方法也可以调用 Java 中的方法和成员变量. Java 中的类封装了属性和方法,想要访问 Java 中的属性和方法,首先要获得 Java ...

  2. Xbox360游戏收藏

    xbox360游戏下载地址 http://dl.3dmgame.com/SoftList_221.html   XBLA游戏总结.http://tieba.baidu.com/p/3174478602 ...

  3. cocos2d js的一些tip

    cocos2d-js-v3.2-rc0 cc.director.end();//退出app cc.Application.getInstance().openURL("http://www. ...

  4. 转-SpringMVC——之 国际化

    原文地址:http://www.cnblogs.com/liukemng/p/3750117.html 在系列(7)中我们讲了数据的格式化显示,Spring在做格式化展示的时候已经做了国际化处理,那么 ...

  5. java封装后引用的例子

    封装好的文件: 另外一个文件引用封装文件的方法: 来源: https://www.runoob.com/java/java-encapsulation.html

  6. log4j示例-Daily方式(log4j.properties)

    log_home=./log log4j.rootLogger=info log4j.category.com.ai.toptea.collection=Console,DailyFile,Daily ...

  7. linux rar安装

    1.wget http://www.rarsoft.com/rar_CN/rarlinux-3.9.3.tar.gz 2.tar 3.make && make install; 4.需 ...

  8. delphi 线程 TTask

    http://docwiki.embarcadero.com/Libraries/Seattle/en/System.Threading.TTask http://docwiki.embarcader ...

  9. SqlServer数据压缩测试

    SqlServer数据压缩测试 环境说明 操作系统:WIN SERVER 2012 R2 Standard 数据库系统: SQLSERVER 2016 SP1 Enterprise Evaluatio ...

  10. 将OCX控件打包成EXE,实现双击后自动注册<转>

    工具:2345好压[其他压缩软件应该大同小异] 第一步:首先将要打包的OCX控件,以及该控件所依赖的DLL文件放到桌面: 第二步:1.新建文本文档,取名 register.txt,文档内写入   re ...