Java的equals方法的使用技巧
Java的equals方法的使用技巧
1.业务场景:
在某个社交软件中,要求每个用户的用户名(name)必须独一无二,那么在每次增加新用户的时候,都要对该用户的注册名进行判断,如果当前用户名已经被占用,则无法为该用户创建账号,只能要求该新用户重新选择设定用户名。
2.解决思路:
考虑到这里比较的每一个用户这样的对象,而其的等价判断标准是name,因此我们可以考虑使用object类自带的equals()方法对其进行比较,其中在方法体中以判断标准name进行返回。
补充:对于不同的数据类型,其比较方式也是不同的。(参考于Effective Java 中文版 第三版)
(1)既不是float也不是double的基本数据类型域:使用 ==
(2)对象引用域:使用 equals()方法
(3)float域:使用 Float.compare(float,float)
(4)double域:使用Double.compare(double,double)
这里对这个实现过程进行模拟。

这里说明一下equals内代码的一般写法:
第一步,先判断引用值是否相等,此时person1.equals(person1)这样的情况,就可以很快返回结果true。
第二步,判断类型是否匹配,如果两个对象等价,前提是它们一定为相同的类型,此时person1.equals(null)这样的情况,也能进行判断并返回结果false。
第三步,按部就班地按照预设的特征值进行对象的等价性判断。
运行结果:

这里说明几点:
1.类中的equals方法是一定要重写/覆盖(Override)的,因为要让它按照设计的需求来根据特征值判断等价性。
这里的特征值,就是String类型的name属性,表示每个Person对象的名字。由于在equals方法中只设定了这一个需要比较的特征值,因此只要两个Person类对象的name相同,那么他们的判断结果就是相同。
3.引伸问题:
事实上,当实现了1之后,就能保证判断两个对象等价性是否成立了(此时已经能保证程序中person1.equals(person2)值为true。但是这样得到的equals方法是有很大限定性的。比如把person1加入到一个HashSet中,此时判断HashSet中是否包含person2,由于在设计时,特征值只是name,那么此时期望HashSet.contains(person2)的值也应为true,但如果不实现hashCode方法,返回值只能是false。
3.1不相等原因:
对于这个原因,可以把Java中每个实例对象的存储过程都想象成“将包含该对象的数据‘抛到’一个桶里”,为了更快地比价,就把整个程序运行时的空间,分成相当多的“桶”,并为每个桶编号,对于桶内装载的数据,有这样的规定:为每个实例对象进行编号,只有编号相同的两个对象,它们才有可能分配到一个桶里。这样一来,要想判断两个对象是否等价(即是否能让equals方法返回true),只需要访问这个桶就可以了,因为这两个对象一定是出现在相同的桶里的。步骤1已经实现了“找到两个对象之后,根据某个特征值进行判断”,但是并未实现“让两个对象分配到一个桶里”。这就是问题的关键所在。
3.2解决思路:
所以为了保证两个对象分配到相同的“桶”里,就要重写它们的hashCode方法,Java中为每种类型都默认实现了该类型的hashCode方法。下面的实现了hashCode的代码中,由于特征值是name,为了保证这两个Person类对象等价,那么它们的name一定相同,那考虑到name(Sting类型)已经实现了hashCode,此时就简单地把它们的name的hashCode值进行返回即可。这样就能保证,如果两个Person对象的name如果相同,那么它们的hashCode一定相同,同时也便于下一步判断。
这里给出未实现hashCode的Person类,并展示其测试代码:

测试结果:

可见,未实现hashCode时,set.contains(person2)为false,即此时HashSet类型在检索person2时,发现它不在其装载对象(perosn1)所在的“桶”里,于是直接返回false。
此时,重新实现代码:

此时再次测试上述测试代码,测试结果:

可以看到,尽管测试set未装载person2,但根据重写的equals判定等价性规则,person2也是被判定符合等价性的,因此在实现了hashCode后,便也能让持有对象按照设定的规则判断其等价性。
4.小结:
现实生活中处处体现着“ADT设计者的智慧”。上述实现代码以及测试都是基于特征值为name来进行实现的,在现实生活中,比如“居民身份证”来说,判断两个对象是否“等价”(即是否为同一个人),特征值自然就包括name(名字),sex(性别),age(年龄)等等属性,考虑到使用居民身份证的频繁使用以及广泛的应用场景,每个居民就理所应当地拥有了一个额外的“属性”: 身份证号。这个独一无二的值,既实现了每个对象的区别,又能很方便地进行排序(从而进行检索等操作)。
Java为程序开发者提供了灵活的设定“特征值”的方法,因此在设计一种需要的数据类型时,可以仔细地思考一下两个对象判断等价的依据(特征值)究竟是什么,这样实现的equals方法,往往给ADT的使用过程带来了极大的便利。
原参考文章链接:Java的equals方法实现及其细节
Java的equals方法的使用技巧的更多相关文章
- java中equals方法和==的用法
java中equals方法的用法以及==的用法(参考一)equals 方法是 java.lang.Object 类的方法.两种用法说明:(1对于字符串变量来说,使用“==”和“equals()”方法比 ...
- java重写equals方法
@Override public int hashCode() { return task.getId(); } @Override public boolean equals(Object obj) ...
- java对象equals方法的重写
根类Object中的equals方法描述: public boolean equals(Object obj)The equals method for class Object implements ...
- 简述java中equals()方法和==的区别
==与equals的主要区别是: ==: ==常用于比较原生类型(基本数据类型):byte,short,char,int,long,float,double,boolean,比较的是他们的值. 若用= ...
- java重写equals方法需要注意的几点
为什么equals()方法要重写? 判断两个对象在逻辑上是否相等,如根据类的成员变量来判断两个类的实例是否相等,而继承Object中的equals方法只能判断两个引用变量是否是同一个对象.这样我们往往 ...
- Java重写equals方法(重点讲解)
为什么equals()方法要重写? 判断两个对象在逻辑上是否相等,如根据类的成员变量来判断两个类的实例是否相等,而继承Object中的equals方法只能判断两个引用变量是否是同一个对象.这样我们往往 ...
- java代码equals方法
package com.bc; public class Test_6 { // 我们知道java中的每个类都继承自Object类,equals是Object方法之一 String name; int ...
- java"=="与equals()方法的对照
总结:String s=new String(); s是在堆内存里的 String s2=new String(); s2是在堆内存又重新生成的一个. package com.da; //逆向思维:i ...
- java基础—equals方法
一.equals方法介绍 1.1.通过下面的例子掌握equals的用法 1 package cn.galc.test; 2 3 public class TestEquals { 4 public s ...
随机推荐
- iOS之Xcode提交App中断出现:Cannot proceed with delivery: an existing transporter instance is currently uploading this package
https://www.jianshu.com/p/6d465a0ea58e 这句英文翻译过来就是: 无法继续交付:现有的传输程序实例目前正在上载此包 原因:上传的动作被记录在UploadToken中 ...
- teraterm中log中加入时间戳
步骤: 1.Setup->Additional settings->log->Timestamp(Local Time) 2.记录log.File->log(Teraterm. ...
- C++运算符重载复习
本人理解运算符重载实质 就类似函数重载 运算符重载都可以写成一个函数 里面传入参数 来调用 运算符重载不是必须的 但是重载后会方便很多. 小例子 一个类实现 ++ 和+某个数重载 大于号重载 ...
- 洛谷P1091合唱队形(DP)
题目描述 NNN位同学站成一排,音乐老师要请其中的(N−KN-KN−K)位同学出列,使得剩下的KKK位同学排成合唱队形. 合唱队形是指这样的一种队形:设K位同学从左到右依次编号为1,2,…,K1,2, ...
- k种球若干,取n个球,输出所有取球方案 (模拟)
有K种颜色的小球(K<=10),每种小球有若干个,总数小于100个. 现在有一个小盒子,能放N个小球(N<=8),现在要从这些小球里挑出N个小球,放满盒子. 想知道有哪些挑选方式.注:每种 ...
- LeetCode困难题(一)
题目一: 给你一个链表,每 k 个节点一组进行翻转,请你返回翻转后的链表. k 是一个正整数,它的值小于或等于链表的长度. 如果节点总数不是 k 的整数倍,那么请将最后剩余的节点保持原有顺序. 示例 ...
- 正确使用 Android 的 Theme 和 Style
原文:http://www.tuicool.com/articles/ZjEZFj Android 5.0 可以给一个 View 单独设置一个 theme 了,其主要用途就是用在 ToolBar 上, ...
- CSS3-边框(border-radius、box-shadow、border-image)
CSS3中的边框属性:border-radius.box-shadow.border-image 圆角:border-radius 使用 CSS3 border-radius 属性,你可以给任何元素制 ...
- 如何使用gcc_clang进行C语言的编译_编译的流程是什么?
编译命令 gcc/clang -g -O2 -o -c test test.c -I... -L... -l -g : 输出文件中的调试信息 -O : 对输出文件做出指令优化,默认是O1, O2优化更 ...
- java set的线程安全
CopyOnWriteArraySet和ConcurrentSkipListSet 与线程不安全的集合类的对应关系 HashSet -> CopyOnWriteArraySet TreeSet ...