Java常见面试问题: equals()与hashCode()的使用
1 equals()与‘==’的区别
默认情况下也就是从超类Object继承而来的equals()方法与‘==’是完全等价的, 比较的都是对象的内存地址.
但我们可以重写equals()方法, 使其按照我们的需求的方式进行比较, 比如String类就重写了equals方法, 它比较的是字符的序列, 而不再是内存地址.
2 equals()方法的重写规则
自反性、对称性、传递性等都是 <集合论> 中的概念.
(1) 自反性: 对于任何非null的引用值x, x.equals(x)应返回true.
(2) 对称性: 对于任何非null的引用值x与y, 当且仅当:y.equals(x)返回true时, x.equals(y)才返回true.
(3) 传递性: 对于任何非null的引用值x、y与z, 如果y.equals(x)返回true, y.equals(z)返回true, 那么x.equals(z)也应返回true.
(4) 一致性: 对于任何非null的引用值x与y, 假设对象上equals比较中的信息没有被修改, 则多次调用x.equals(y)始终返回true或者始终返回false.
(5) 对于任何非空引用值x, x.equal(null)应返回false.
3 为什么重写equals()的同时还需要重写hashCode()
这个问题主要和映射(Map接口)相关. 我们知道Map接口的类会使用到键(Key)的哈希码, 当我们调用put()/get()方法操作Map容器时, 都是根据Key的哈希码来计算存储位置的, 因此如果我们对哈希码的获取没有相关保证, 就可能会得不到预期的结果.
在Java中, 我们可以通过hashCode()方法获取对象的哈希码, 哈希码的值就是对象的存储地址, 这个方法在Object类中声明, 因此所有的子类都含有该方法.
hashCode就是哈希码(或者散列码), 是由对象导出的一个整型值, 哈希码是没有规律的, 如果x与y是两个不同的对象, 那么x.hashCode()与y.hashCode()就不会相同 —— 只要x和y对象没有重写hashCode()方法, JVM规范中明确要求它们的散列码不会相同.
String(字符串)的哈希码是由字符串的内容导出的, 也就是String类中重写了hashCode()方法.
4 JDK 7中对hashCode()方法的改进
(1) Java发布者希望我们使用更加安全的调用方式来返回散列码, 也就是使用null安全的java.util.Objects.hashCode()方法, 这个方法的优点是如果参数为null, 就只返回0, 否则返回对象参数调用的hashCode的结果.
Objects.hashCode()的源码如下:
public static int hashCode(Object o) {
return o != null ? o.hashCode() : 0;
}
(2) JDK 7中还提供了一个方法: java.util.Objects.hash(Object... objects), 当需要组合多个散列值时可以调用该方法, 比如:
public class Model {
private String name;
private double salary;
private int sex;
// @Override
// public int hashCode() {
// return Objects.hashCode(name) + new Double(salary).hashCode() + new Integer(sex).hashCode();
// } @Override
public int hashCode() {
return Objects.hash(name, salary, sex);
}
}
扩展: 如果我们提供的是一个数值类型的变量, 那么我们可以调用Arrays.hashCode()方法来计算它的散列码, 这个散列码是由数组中各个元素的散列码组成的.
5 Java API文档中关于hashCode()方法的规定
—— 内容摘自《Java深入解析》.
(1) 在Java应用程序执行期间, 如果在equals()方法中涉及到的信息没有被修改, 那么在同一个对象上多次调用hashCode()方法时必须一致地返回相同的整数. 如果多次执行同一个应用程序时, 不要求该整数必须相同.
(2) 如果两个对象通过调用equals()方法是相等的, 那么这两个对象调用hashCode()方法必须返回相同的整数.
(3) 如果两个对象通过调用equals()方法是不相等的, 不要求这两个对象调用hashCode()方法必须返回不同的整数. 但是开发人员应该意识到: 对不同的对象产生不同的hash值可以提高哈希表的性能.
6 重写equals()方法时推荐使用getClass(), 而不是instanceof
在重写equals()方法时, 一般推荐使用getClass()来进行类型判断, 而不是使用instanceof关键字.
除非所有的子类有统一的语义才使用
instanceof, 统一的语义就是说, 不同的子类在equals()方法中比较的内容相同.
我们知道, instanceof关键字的作用是判断其左边对象是否为其右边类型的实例, 返回boolean类型的数据, 它多用来判断继承关系中的某个子类的实例是否为父类的实现.
7 编写一个完美的equals()方法的建议
—— 摘自《Java核心技术 第一卷:基础知识》.
(1) 显式参数命名为otherObject, 稍后需要将它转换成另一个叫做other的变量 (参数名命名, 强制转换请参考下一条建议);
(2) 将otherObject转换为相应的类类型变量: ClassName other = (ClassName) otherObject;;
(3) 检测this与otherObject是否引用同一个对象: if(this == otherObject) return true; —— 存储地址相同, 肯定是同个对象, 直接返回true;
(4) 检测otherObject是否为null , 如果为null, 返回false: if(otherObject == null) return false;;
(5) 比较this与otherObject是否属于同一个类(视需求而选择):
① 如果equals的语义(可以理解为equals比较的内容)在每个子类中有所改变, 就使用getClass检测:
if(getClass() != otherObject.getClass()) return false;② 如果所有的子类都拥有统一的语义(比较的内容不变), 就使用instanceof检测:
if(!(otherObject instanceof ClassName)) return false;
(6) 对所有需要比较的域进行比较: 使用==比较基本类型域, 使用equals比较对象域. 如果所有的域都匹配, 就返回true, 否则就返回flase:
① 如果在子类中重新定义equals()方法, 就要在其中包含调用
super.equals(other);② 当此方法被重写时, 通常有必要重写 hashCode() 方法, 以维护 hashCode 方法的常规协定, 该协定声明 相等对象必须具有相等的哈希码
参考资料
版权声明
作者: 马瘦风
出处: 博客园 马瘦风的博客
感谢阅读, 如果文章有帮助或启发到你, 点个[好文要顶
Java常见面试问题: equals()与hashCode()的使用的更多相关文章
- java中的==、equals()、hashCode()源码分析(转载)
在java编程或者面试中经常会遇到 == .equals()的比较.自己看了看源码,结合实际的编程总结一下. 1. == java中的==是比较两个对象在JVM中的地址.比较好理解.看下面的代码: ...
- java中的==、equals()、hashCode()
java中的==.equals().hashCode()源码分析 在java编程或者面试中经常会遇到 == .equals()的比较.自己看了看源码,结合实际的编程总结一下. 1. == java中 ...
- java基础(十六)----- equals()与hashCode()方法详解 —— 面试必问
本文将详解 equals()与hashCode()方法 概述 java.lang.Object类中有两个非常重要的方法: public boolean equals(Object obj) publi ...
- java中的==、equals()、hashCode()源码分析
转载自:http://www.cnblogs.com/xudong-bupt/p/3960177.html 在Java编程或者面试中经常会遇到 == .equals()的比较.自己看了看源码,结合实际 ...
- Java双等号,Equals(),HashCode()小结
默认情况 - 双等号==,比较的是内存地址. - equals(),默认比较的是内存地址. - hashCode(),默认返回的是object的内存地址. String中方法改写的情况 经常会遇到需要 ...
- Java Hash集合的equals()与hashCode() 方法
Java 集合实现类,无论是HashSet.HashMap等所有的Hash算法实现的集合类(后面简称Hash集合),加入的对象必须实现 hashCode() 与 equals() 方法,稍微不同的地方 ...
- java常见面试题目(一)
在大四实习阶段,秋招的时候,面试了很多家公司,总结常见的java面试题目:(答案可以自己百度) 1.你所用oracle的版本号是多少? 2.tomcat修改8080端口号的配置文件是哪个? 3.myb ...
- java常见面试题目
(面的初级到中级之间的,却有很多高级的问题) 总结一些常见的遇见的面试题(来自各方面收集) 1.开发中Java用了比较多的数据结构有哪些? 2.谈谈你对HashMap的理解,底层原理的基本实现,Has ...
- Java Object中的equals和hashCode
Java的Object对象中有两个方法比较有意思,一个是equals(),一个是hashCode(),那么这两个的作用有些同学可能还不是很清楚,那么同学们现在就进一步了解一下吧. 下面咱们写一个简单的 ...
随机推荐
- Python学习系列之反射
反射的定义 根据字符串的形式去某个对象中操作成员 根据字符串的形式去某个对象中寻找成员 根据字符串的形式去某个对象中设置成员 根据字符串的形式去某个对象中删除成员 根据字符串的形式去某个对象中判断成员 ...
- LintCode 近期公共祖先
中等 近期公共祖先 查看执行结果 34% 通过 给定一棵二叉树,找到两个节点的近期公共父节点(LCA). 近期公共祖先是两个节点的公共的祖先节点且具有最大深度. 您在真实的面试中是否遇到过这个题? Y ...
- js 返回顶部
<script> window.onload = function(){ var oTop = document.getElementById("to_top"); v ...
- MFC中SliderCtrl控件的使用
在MFC中滑动条(CSliderCtrl)是个经常使用的控件,使用方法例如以下: 主要要方法有: 1.设置.取得滑动范围: void SetRange( int nMin, int nMax, BOO ...
- where 1=1影响效率以及having和where的区别
低效的“WHERE 1=1” 网上有不少人提出过类似的问题:“看到有人写了WHERE 1=1这样的SQL,到底是什么意 思?”. 其实使用这种用法的开发人员一般都是在使用动态组装的SQL. 让我们想像 ...
- POJ 3100:Root of the Problem
Root of the Problem Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 12060 Accepted: 6 ...
- 【Dairy】2016.10.17-1 OIer最悲剧的事情
OIer最悲剧的事情: 看完题,觉得很可做 然后开始码,码了很久 一测样例,不过.. 开始肉眼查错..手玩样例.. 过了很久 ...
- C#数字、16进制字符串和字节之间互转
转自http://luohonghong.blog.163.com/blog/static/78312058201242632055642/ 如下: .数字和字节之间互转 ; byte[] bytes ...
- build_native.py文件分析(2)
def build(ndk_build_param,android_platform,build_mode): ////获取ndk_root -- NDK_ROOT = os.environ['NDK ...
- 洛谷 P1131 [ ZJOI 2007 ] 时态同步 —— 树形DP
题目:https://www.luogu.org/problemnew/show/P1131 记录 x 子树内同步的时间 f[x],同步所需代价 g[x]: 直接转移即可,让该儿子子树与其它儿子同步, ...