前言

万丈高楼平地起,今天的聊点基础而又经常让人忽视的话题,比如“==”与“equals()”区别?为何当我们重写完"equals()"后也要有必要去重写"hashcode()"呢? ... 带着这些问题,我们一起来探究一下。

概念

"==":它主要是判断符号两边的“对象”的值是否相等,而这里的“值“”又有所区分了。

  • 基础数据类型:比较的就是自身的值,这个跟我们常规的理解是基本一致的。

  • 引用数据类型:比较的对象的内存地址。

“equals()”:它也是用来判断两个对象是否相等,所以也得分不同的情况来说明。

  • 在当前类中,没有重写equals方法的话,默认的实现跟"=="的实现是一样的。下面是Object类的equals方法实现。

  • 在当前类中,重写了equals方法,此时判断的依据就是你重写的逻辑。

怎样重写equals()方法?

1、自反性:对于任何非空引用x,x.equals(x)应该返回true。
2、对称性:对于任何引用x和y,如果x.equals(y)返回true,那么y.equals(x)也应该返回true。
3、传递性:对于任何引用x、y和z,如果x.equals(y)返回true,y.equals(z)返回true,那么x.equals(z)也应该返回true。
4、一致性:如果x和y引用的对象没有发生变化,那么反复调用x.equals(y)应该返回同样的结果。
5、非空性:对于任意非空引用x,x.equals(null)应该返回false。

由此可以看出,重写一个equals()方法,需要注意的点还是比较多的,这里给出一个参考的事例。

public class EqualsDemo {
private String name;
private String info; @Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false; EqualsDemo that = (EqualsDemo) o; if (name != null ? !name.equals(that.name) : that.name != null) return false;
return info != null ? info.equals(that.info) : that.info == null;
} @Override
public int hashCode() {
int result = name != null ? name.hashCode() : 0;
result = 31 * result + (info != null ? info.hashCode() : 0);
return result;
}
}

有些读者可能会感到奇怪,不是说重写equals()方法吗,为什么这里又出现了一个hashcode()?所以这里又引出了我们的另一个主角hashcode()方法,当我们重写了equals()方法后,它就一定会出现,也会“吵着“自己也要被重写。

什么是hashcode()?

hashCode() 的作用是获取哈希码,也称为散列码;它返回的一个int整数。这个哈希码的作用是确定该对象在哈希表中的索引位置。hashCode方法的主要作用是为了配合基于散列的集合一起正常运行,这样的散列集合包括HashSet、HashMap、HashTable等。它定义在JDK的Object.java中,这就意味着Java中的任何类都包含有hashCode() 函数。

当我们在上面的集合插入对象的时候,java是怎么知道里面是否有重复的对象呢?可能大家第一反应是equals方法,没错这方法可以实现这个功能,但是当集合里面有成千上万个元素的时候,效率会如何呢?答案当然是比较差了,所以才会出现了哈希码。

public V put(K key, V value) {
//判断当前数组是否等于{},若是则初始化数组
if (table == EMPTY_TABLE) {
inflateTable(threshold);
}
//判断 key 是否等于 null,是则将把当前键值对添加进table[0]中,遍历table[0]链表
//如果已经有null为key的Entry,则修改值,返回旧值,若无则直接添加。
if (key == null)
return putForNullKey(value);
//key不为null则计算hash
int hash = hash(key);
//搜索对应hash所在的table中的索引
int i = indexFor(hash, table.length);
for (Entry<K,V> e = table[i]; e != null; e = e.next) {
Object k;
if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
V oldValue = e.value;
e.value = value;
e.recordAccess(this);
return oldValue;
}
}
//修改次数
modCount++;
addEntry(hash, key, value, i);
return null;
}
 

这里是jdk7中 Hashmap put()方法的实现,通过源码的注释可以看出执行的流程,需要更详细的了解HashMap可以参考我之前发在开源中国的博客《Java7  HashMap全面解读! 》,链接:https://my.oschina.net/19921228/blog/752073

经过概念的介绍,知道为什么重写完equals()后要接着重写hashcode()了吧?

People p1=new People("小明",18);

People p2=new People("小明",18);

此时重写了equals方法,p1.equals(p2)一定返回true,假如只重写equals而不重写hashcode,那么Student类的hashcode方法就是Object默认的hashcode方法,由于默认的hashcode方法是根据对象的内存地址经哈希算法得来的,显然此时s1!=s2,故两者的hashcode不一定相等。所以在一些集合的使用当中会出现问题。

总结 

 

小小的几个方法,没想到却有这么多“坑”,而且在面试中也会经常被问到,在金三银四的时候,但愿各位不会陷在这里。

------------------------------------------------------

【推荐阅读】

大白话搞懂什么是同步/异步/阻塞/非阻塞

Java异常处理最佳实践及陷阱防范

论JVM爆炸的几种姿势及自救方法

看完本文有收获?请转发分享给朋友吧

关注「深夜里的程序猿」,分享最干的干货

“==”、“equals()”、“hashcode()”之间的秘密的更多相关文章

  1. JavaSE的包装类,自动装箱和自动拆箱 ,字符窜转换,toString(),equals(), hashCode()的区别

    一.基本数据类型和包装类 包装类均位于Java.lang包,包装类和基本数据类型的对应关系如下表所示: Primitive-Type   Wrapper-Class        byte       ...

  2. equals(),hashcode(),克隆学习心得

    equals(),hashcode(),克隆学习心得 其实在开发时候,很少去重写equals(),hashCode()方法,但是有些时候业务需要还是要重写. 注意: 重写equals()方法一定要重写 ...

  3. 讲的很详细的一篇关于object equals() & hashCode() 的文章

    转: 讲的很详细的一篇关于object equals() & hashCode() 的文章 哈希表这个数据结构想必大多数人都不陌生,而且在很多地方都会利用到hash表来提高查找效率.在Java ...

  4. java中的 equals + hashCode

    [0]README 0.1)本文转自 core java volume 1, 旨在理清 equals + hashCode方法: [1]equals方法 1.1) Object中的 equals 方法 ...

  5. 在@Data注释lombok上使用继承警告等于/ hashCode(Warning equals/hashCode on @Data annotation lombok with inheritance)

    生成equals / hashCode实现但没有调用超类,即使这个类没有扩展java.lang.Object.如果这是故意的,请将 @EqualsAndHashCode(callSuper = fal ...

  6. equals()和hashCode()之间的关系

    在Java的基类java.lang.Object中有两个非常重要的方法: public boolean equals(Object obj) public int hashCode() 对这两个方法的 ...

  7. "=="、equals、hashCode之间的区别

    1. "=="分为两种情况: (1) 基本数据类型,比较的是其对应的值是否相等: (2) 引用类型,比较的是他们在内存中存放的地址(或者说,是否指向同意对象). 2. equals ...

  8. java里equals和hashCode之间什么关系

    如果要比较实际内存中的内容,那就要用equals方法,但是!!! 如果是你自己定义的一个类,比较自定义类用equals和==是一样的,都是比较句柄地址,因为自定义的类是继承于object,而objec ...

  9. == equals hashCode 总结比较

    在Java中: ==是运算符,用于比较两个变量是否相等. equals,是Objec类的方法,用于比较两个对象是否相等,默认Object类的equals方法是比较两个对象的地址,跟==的结果一样.Ob ...

随机推荐

  1. (汇总)os模块以及shutil模块对文件的操作

    ''' # os 模块 os.sep 可以取代操作系统特定的路径分隔符.windows下为 '\\' os.name 字符串指示你正在使用的平台.比如对于Windows,它是'nt',而对于Linux ...

  2. Android自动化框架介绍

    随着Android应用得越来越广,越来越多的公司推出了自己移动应用测试平台.例如,百度的MTC.东软易测云.Testin云测试平台…….由于自己所在项目组就是做终端测试工具的,故抽空了解了下几种常见的 ...

  3. C语言下double转char*或者std::string,可以精确转换不含多余的0

    char* GetDoubleStr(double value) { char buf[32]={0};//长度可以自定义 sprintf(buf,"%.8f",value);// ...

  4. Python 3.6 中文手册——前言

    1. 前言 如果你在电脑上做了很多工作,最终你会发现有一些任务你想要自动化.例如,你可能希望对大量的文本文件执行搜索和替换,或者以复杂的方式重命名并排列一堆照片文件.也许你想写一个小的自定义数据库,或 ...

  5. MySQL复制进阶

    Ⅰ.背景 搭建MySQL复制环境非常简单 你的系统是否也是像我之前那么搭建的呢? 那么,你的复制系统是否出现过以下的情况呢? 复制报错,例如:1062,1032 主从数据不一致 Ⅱ.真正高可靠复制环境 ...

  6. error: src refspec XXX matches more than one

    error: dst refspec v1. matches more than one. error: failed to push some refs to '' 错误原因是 branch名和ta ...

  7. 这样入门asp.net core,如何

    本文章主要说明asp.net core的创建和简单使用. 一.使用到的命令 dotnet new :创建项目(解决方案,类库,单元测试等),如:dotnet new web dotnet add pa ...

  8. Autopep8的使用

    什么是Autopep8 在python开发中, 大家都知道,python编码规范是PEP8,但是在市级开发中有的公司严格要求PEP8规范开发, 有的公司不会在乎那些,在我的理解中,程序员如果想走的更高 ...

  9. 更改eclipse的编辑器样式风格

    这里提供两种方法: 1.从网站http://eclipsecolorthemes.org/ 下载,选好自己喜欢的风格后下载epf文件...再使用eclipse的import->preferenc ...

  10. Android 打造编译时注解解析框架 这只是一个开始

    转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/43452969 ,本文出自:[张鸿洋的博客] 1.概述 记得很久以前,写过几篇博客 ...