今天朋友突然问到一个问题:两个对象使用x.equals(y)判断结果为true时,两个对象的hashCode可以不同吗?

在Java编程中,判断两个对象是否相等常常使用equals()或是==,但是其中的区别和原理可能很多人并不完全清楚。今天就借着上面这个问题来看看equals()和==的区别和原理。

1. 数据类型与==的含义

Java中的数据类型分为基本数据类型和引用数据类型:基本类型:编程语言中内置的最小粒度的数据类型。它包括四大类八种类型4种整数类型:byte、short、int、long

2种浮点数类型:float、double

1种字符类型:char

1种布尔类型:boolean

引用类型:引用也叫句柄,引用类型,是编程语言中定义的在句柄中存放着实际内容所在地址的地址值的一种数据形式类

接口

数组

对于基本类型来说,== 比较的是它们的值

对于引用类型来说,== 比较的是它们在内存中存放的地址(堆内存地址)

例:

public void test(){

int num1 = 100;

int num2 = 100;

String str1 = "James";

String str2 = "James";

String str3 = new String("James");

String str4 = new String("James");

System.out.println("num1 == num2 : " + (num1 == num2));

System.out.println("str1 address : " + System.identityHashCode(str1) + ";\nstr2 address : " + System.identityHashCode(str1) + ";\nstr1 == str2 : " + (str1 == str2));

System.out.println("str3 address : " + System.identityHashCode(str3) + ";\nstr4 address : " + System.identityHashCode(str4) + ";\nstr3 == str4 : " + (str3 == str4));

}

运行上面的代码,可以得到以下结果:

num1 == num2 : true

str1 address : 1174290147;

str2 address : 1174290147;

str1 == str2 : true

str3 address : 1289696681;

str4 address : 1285044316;

str3 == str4 : false

可以看到str1和str2的内存地址都是1174290147,所以使用==判断为true,但是str3和str4的地址是不同的,所以判断为false。

2. equals() 方法解析

在Java语言中,所有类都是继承于Object这个超类的,在这个类中也有一个equals()方法,那么我们先来看一下这个方法。

public boolean equals(Object obj) {

return (this == obj);

}

可以看得出,这个方法很简单,就是比较对象的内存地址的。所以在对象没有重写这个方法时,默认使用此方法,即比较对象的内存地址值。但是类似于String、Integer等类均已重写了equals()。下面以String为例。

public boolean equals(Object anObject) {

if (this == anObject) {

return true;

}

if (anObject instanceof String) {

String anotherString = (String)anObject;

int n = length();

if (n == anotherString.length()) {

int i = 0;

while (n-- != 0) {

if (charAt(i) != anotherString.charAt(i))

return false;

i++;

}

return true;

}

}

return false;

}

很明显,String的equals()方法仅仅是对比它的 数据值,而不是对象的 内存地址 。

以 String 为例测试一下。

public void test() {

String str1 = "James";

String str2 = "James";

String str3 = new String("James");

String str4 = new String("James");

System.out.println("str1 address : " + System.identityHashCode(str1) + ";\nstr2 address : " + System.identityHashCode(str1) + ";\nstr1.equals(str2) : " + str1.equals(str2));

System.out.println("str3 address : " + System.identityHashCode(str3) + ";\nstr4 address : " + System.identityHashCode(str4) + ";\nstr3.equals(str4) : " + str3.equals(str4));

}

结果为:

str1 address : 1174290147;

str2 address : 1174290147;

str1.equals(str2) : true

str3 address : 1289696681;

str4 address : 1285044316;

str3.equals(str4) : true

可以发现不管对象的内存地址是否相同并不影响其结果,所以String类型比较的是 数据值, 而不是 内存地址值。

所以总结一下equals() 和 == 的区别:==基本类型:对比它们的值是否相等

引用类型:对比它们的内存地址是否相等equals()基本类型:使用==进行比较

引用类型:默认情况下,对比它们的地址是否相等;如果equals()方法被重写,则根据重写的要求来比较。

3. equals() 与 hashCode()

在详细的了解了==和equals()的作用和区别后,现在来研究一下之前的那个问题:两个对象使用x.equals(y)判断结果为true时,两个对象的hashCode可以不同吗?

首先我们需要知道hashCode到底是什么?还是从Object这个超类来看一下。

public int hashCode() {

return identityHashCode(this); // 此处返回对象的内存地址值

}

代码也很简单,看来默认情况下,hashCode就等于对象的 内存地址值(注:System.identityHashCode(Object obj)方法用于获取对象的内存地址,之前的样例代码中有使用)。和equals()方法一样重写之后,hashCode()方法方法也是可以被重写的,而且两者一般情况下都是成对出现。

简单测试一下String类型重写hashCode()方法之后有什么变化。

public void test() {

String str1 = "James";

System.out.println("str1 address : " + System.identityHashCode(str1) + "\nstr1 hashCode : " + str1.hashCode());

}

结果为:

str1 address : 1174290147

str1 hashCode : 71338276

很明显,hashCode 已经不是内存地址了。

那么总结一下:equals():默认情况下比较的是对象的 内存地址值,被重写后按照重写要求进行比较,一般是比较对象的 数据值

hashCode(): 默认情况下为对象的 内存地址值,被重写后按照重写要求生成新的值。

到此对于刚开始提出的问题应该很好解决了。对于这两个对象,只要我们重写equals()方法,就可以比较对象的 数据值,而不重写hashCode()方法,此时两个对象的 hashCode 就默认为内存地址值了,只要将两个对象指向不同的地址即可。

验证环节,先创建一个类:

public class CustomBean {

private String name;

private int age;

public CustomBean(String name, int age) {

this.name = name;

this.age = age;

}

@Override

public boolean equals(Object o) {

if (this == o) return true;

if (o == null || getClass() != o.getClass()) return false;

CustomBean that = (CustomBean) o;

return age == that.age &&

Objects.equals(name, that.name);

}

// @Override

// public int hashCode() {

// return Objects.hash(name, age);

// }

}

创建测试方法:

@Test

public void test() {

CustomBean x = new CustomBean("James", 18);

CustomBean y = new CustomBean("James", 18);

System.out.println("x.hashCode: " + x.hashCode());

System.out.println("x address : " + System.identityHashCode(x));

System.out.println("y.hashCode: " + y.hashCode());

System.out.println("x address : " + System.identityHashCode(y));

System.out.println("x and y is equals : " + x.equals(y));

}

运行结果为:

x.hashCode: 1174290147

x address : 1174290147

y.hashCode: 1289696681

x address : 1289696681

x and y is equals : true

很明显,这就是问题中所描述的那种情况:两个对象使用x.equals(y)判断结果为true时,两个对象的hashCode不相同。

4. 总结

至此,==和equals()的区别及作用,equals()和hashCode的关系及使用已经了解清楚了。下面再总结一下:

对于equals() 和 == 的区别:==基本类型:对比它们的值是否相等

引用类型:对比它们的内存地址是否相等

equals()基本类型:使用==进行比较

引用类型:默认情况下,对比它们的地址是否相等;如果equals()方法被重写,则根据重写的要求来比较

对于equals()和hashCode()的关系:

根据Object超类中的文档说明,equals()和hashCode()两个方法应该 同进同退。上面的例子只是举例说明存在那种情况,但那并不是一个很好的应用。所以一定要记住equals()和hashCode()两个方法应该 同进同退。

所以一定要记住equals()和hashCode()两个方法应该 同进同退。

所以一定要记住equals()和hashCode()两个方法应该 同进同退。

重要的事情说三遍。

java andequal_Java equals 和 == 完全解析相关推荐

  1. 2013第四届蓝桥杯Java组省赛题解析

    2013第四届蓝桥杯Java组省赛题解析 目录 第一题:高斯日记 第二题:马虎的算式 第三题:第39级台阶 第四题:黄金连分数 ​第五题:前缀判断 第六题:三部排序 ​第七题:错误票据 第八题:翻硬币 ...

  2. java中equals,hashcode和==的区别

    原文地址http://blog.csdn.net/hla199106/article/details/46907725 1.== java中的数据类型,可分为两类: 1.基本数据类型,也称原始数据类型 ...

  3. Java 调用Google Map Api解析地址,解析经纬度实例

    Java 调用Google Map Api解析地址,解析经纬度实例 使用google地图的反向地址解析功能,提供一个经纬度得到对应地址,或者给出模糊地址,得到经纬度,放在java后台代码中处理,这个使 ...

  4. XML解析 (JAVA解析xml文件)java+Dom4j+Xpath xml文件解析根据子节点得到父节点 查找校验xml文件中相同的节点属性值 java遍历文件夹解析XML

    XML解析 (JAVA解析xml文件)java+Dom4j+Xpath xml文件解析根据子节点得到父节点 以及查找xml文件中相同的节点属性值 项目背景:这是本人实习中所碰到的项目,当时感觉很棘手, ...

  5. Java中四种XML解析技术之不完全测试

    Java中四种XML解析技术之不完全测试 <script language=javascript src=""></script> 在平时工作中,难免会遇到 ...

  6. Java I/O读取和解析.emp文件示例

    Java I/O读取和解析.emp文件示例 1.使用到的知识点 2.示例1 2.1存储几个员工数据到不同的文件 2.1.1题目要求 2.1.2相关代码 2.1.3结果展示 2.2读取存储数据的文件 2 ...

  7. JAVA 中equals()与==的区别

    原文地址:http://www.chineselinuxuniversity.net/articles/29594.shtml 值类型是存储在内存中的堆栈(以后简称栈),而引用类型的变量在栈中仅仅是存 ...

  8. Java中的static关键字解析 转载

    原文链接:http://www.cnblogs.com/dolphin0520/p/3799052.html Java中的static关键字解析 static关键字是很多朋友在编写代码和阅读代码时碰到 ...

  9. java蓝桥杯凑算是,第七届蓝桥杯JAVA B组真题解析-凑算式(第三题)

    第七届蓝桥杯JAVA B组真题解析-凑算式(第三题) 凑算式 A+B/C+DEF/GHI =10 (如果显示有问题,可以参见[图1.jpg]) 这个算式中AI代表19的数字,不同的字母代表不同的数字. ...

最新文章

  1. 手把手教你搭建一个学习Python好看的 Jupyter 环境
  2. 特征选择的通俗讲解!
  3. SAP WM初阶之LX09查询TR List
  4. 跟小静学CLR via C#(12)-委托Delegate
  5. 直播预告 | 亚马逊高级应用科学家熊元骏:人类行为理解研究进展
  6. MySQL高级 - MyISAM特性
  7. 欢乐ssl暑假赛【2019.8.6】
  8. C++数据抽象和问题求解(第6版)
  9. oracle里的关键字有哪些,oracle中的一些关键字
  10. 【原创】ourphp一处SQL注射
  11. API之实用工具Postman 使用方法
  12. 神舟计算机主板bios,神舟笔记本BIOS设置详解
  13. python中文乱码解决
  14. PV、EV、AC、BAC、EAC、ETC等的含义及计算公式
  15. 计算机 无法自检,电脑开机不能自检的五大原因
  16. linux 日志报警,linux日志报警怎么解决
  17. Office2007 Professional简体中文版 附注册码
  18. java web 漏洞扫描工具_java编写web漏洞扫描系列 一、GET/POST
  19. 信息爆炸时代,如何获取优质信息?
  20. 面试软通动力运维面经 2019-05

热门文章

  1. 魔兽服务器排队微信,服务器排队严重:《魔兽世界》经典怀旧服执行47服免费角色转移计划...
  2. RPG Maker MV-自定义人物
  3. c语言——结构体数组——学生成绩表
  4. asp上传文件到ftp服务器,ASP.NET 中使用 FTP 上传文件
  5. python dict是什么意思,python中的字典是什么
  6. “梅西”式核心员工,正在摧毁你的团队
  7. android获取用户手机信息,Android – 使用AccountManager /手机所有者的姓氏和姓氏获取用户数据...
  8. java 读取db3 数据库_db4o(db3文件是什么数据库)
  9. JavaFXでJava RIA開発はどれくらい変わるの?
  10. html网页添加背景音乐