Java中的对象要怎样才算相等
一、引用相等性与对象相等性
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(第二版)》
Java中的对象要怎样才算相等的更多相关文章
- Java中的对象池技术
java中的对象池技术,是为了方便快捷地创建某些对象而出现的,当需要一个对象时,就可以从池中取一个出来(如果池中没有则创建一个),则在需要重复重复创建相等变量时节省了很多时间.对象池其实也就是一个内存 ...
- 【Java基础】Java中new对象的过程
序言 联系我上次写的关于Java内存的文章,对象访问在 Java 语言中无处不在,是最普通的程序行为,但即使是最简单的访问,也会却涉及 Java 栈.Java 堆.方法区这三个最重要内存区域之间的关联 ...
- 浅谈Java中的对象和引用
浅谈Java中的对象和对象引用 在Java中,有一组名词经常一起出现,它们就是“对象和对象引用”,很多朋友在初学Java的时候可能经常会混淆这2个概念,觉得它们是一回事,事实上则不然.今天我们就来一起 ...
- 【译】Java中的对象序列化
前言 好久没翻译simple java了,睡前来一篇. 译文链接: http://www.programcreek.com/2014/01/java-serialization/ 什么是对象序列化 在 ...
- java中直接打印对象
java中直接打印对象,会调用对象.toString()方法.如果没有重写toString()方法会输出"类名+@+hasCode"值,hasCode是一个十六进制数 //没有重写 ...
- 如何使用java中的对象
使用java中的对象,分2步: 1.创建一个对象: 2.使用对象的属性和方法. 见下面的示例代码: package com.imooc; //1.定义一个类 public class Telphone ...
- Java中String对象的不可变性
首先看一个程序 package reverse; public class Reverse { public static void main(String[] args) { String c1=n ...
- JAVA中JavaBean对象之间拷贝的方法
JAVA中JavaBean对象之间的拷贝通常是用get/set方法,但如果你有两个属性相同的JavaBean或有大部分属性相同的JavaBean,有个更简便的方法,他们之间的拷贝可以通过copyPro ...
- Java中计算对象的大小
一.计算对象大小的方法 Java中如何计算对象的大小呢,找到了4种方法: 1.java.lang.instrument.Instrumentation的getObjectSize方法: 2.BTrac ...
随机推荐
- centos7下安装Anaconda3
下载anaconda3: wget https://mirrors.tuna.tsinghua.edu.cn/anaconda/archive/Anaconda3-4.2.0-Linux-x86_64 ...
- awk&sed 小实例
1.打印文件奇数行sed -n 'p;n'sed 'n;d' sed -n '$!N;P'sed -n '1~2p'awk 'i=!i'awk 'NR%2'2.打印文件偶数行sed -n 'n;p's ...
- Erlang generic standard behaviours -- gen_server hibernate
hibernate 主要用于在内存空闲时,通过整理进程的stack,回收进程的heap 来达到回收内存节省资源的效果. hibernate 可用于OTP 进程以及普通进程, hibernate 的官方 ...
- js实现定时调用的函数setInterval()
setInterval是一个实现定时调用的函数,可按照指定的周期(以毫秒计)来调用函数或计算表达式.setInterval方法会不停地调用函数,直到 clearInterval被调用或窗口被关闭 定义 ...
- [Java.Web][Servlet]常用请求头.断点续传
HTTP 请求头字段 Range Range 头指示服务器只传输一部分 Web 资源.这个头可以用来实现断点续传功能. Range 字段可以通过三种格式设置要传输的字节范围: Range bytes ...
- Debian 7.0.0 安装教程图解
Debian7.0.0的安装镜像文件有3个DVD,安装基本系统只用到第一个镜像文件,即DVD1,其它镜像文件是附带的软件包,下面是安装方法 一.说明: Debian7.0.0的安装镜像文件有3个D ...
- mysql 存储过程简单学习
转载自:http://blog.chinaunix.net/uid-23302288-id-3785111.html ■存储过程Stored Procedure 存储过程就是保存一系列SQL命令的集合 ...
- Oracle关于date类型数据的总结
往Oracle数据库中插入日期型数据(to_date的用法) INSERT INTO FLOOR VALUES ( to_date ( '2007-12-20 18:31:34' , 'YYY ...
- html中的一些常用的样式标签
html中的一些常用的样式标签 <p>这里是文本,<mark>高亮</mark></p> <strong>加粗,加重语气</stron ...
- <转>Python3.x和Python2.x的区别
这个星期开始学习Python了,因为看的书都是基于Python2.x,而且我安装的是Python3.1,所以书上写的地方好多都不适用于Python3.1,特意在Google上search了一下3.x和 ...