Java基础之equals和==的区别深入解析
Java基础之equals和==的区别深入解析
以下是本文目录大纲
- equals 和 == 的区别
- equals 的重写
- 复写hashCode方法,有31这个数字的作用
1. equals 和 == 的区别
// object类下的equals
public boolean equals(Object obj) {return (this == obj);}
//String类下的euqals
public boolean equals(Object anObject) {if (this == anObject) {return true;}if (anObject instanceof String) {String anotherString = (String)anObject;int n = value.length;if (n == anotherString.value.length) {char v1[] = value;char v2[] = anotherString.value;int i = 0;while (n-- != 0) {if (v1[i] != v2[i])return false;i++;}return true;}}return false;}
- 首先,我们知道 == 既可以比较基本类型也可以比较引用类型。对于基本类型就是比较值,对于引用类型就是比较内存地址。
- 通过equals源码可以看出,equals是java.lang.Object类里面的方法,如果该方法没有被重写过默认也是==,String类的equals方法是被重写过的,先比length是否相同,相同再比较value是否相同,且String类在日常开发中用的比较多,久而久之,形成了equals是比较值的错误观点
接下来我们再看个代码加深理解
public class stringTest {public static void main(String[] args) {String s1 = new String("abc");String s2 = new String("abc");System.out.println(s1==s2);System.out.println(s1.equals(s2));System.out.println("======================");Set<String> set = new HashSet<>();set.add(s1);set.add(s2);System.out.println(s1.hashCode()+"\t"+s2.hashCode());System.out.println(set.size());System.out.println("============");Person p1 = new Person("abc");Person p2 = new Person("abc");System.out.println(p1 == p2);System.out.println(p1.equals(p2));Set<Person> set2 = new HashSet<Person>();set2.add(p1);set2.add(p2);System.out.println(p1.hashCode()+"\t"+p2.hashCode());System.out.println(set2.size());}}
结果:
false
true
======================
96354 96354
1
============
false
false
1163157884 1956725890
2
解释:
- s1,s2是引用类型且是String类型(即equals方法有重写)
- s1==s2 比较的是内存地址,所以 false
- s1.equals(s2) 的equals重写过,先比较length,再比较value,所以true
- 复写后s1,s2是同一个对象,所以hashCore值相同
- 即能解释 set.size() = 1
同理可以解释p1和p2
- p1,p2为引用类型且是Person类型(即equals没有重写)
- p1==p2 比较的是内存地址,所以 false
- s1.equals(s2) 的equals没有重写过等价于==,所以false
- p1,p2是两个对象,所以hashCore值不相同
- 即能解释 set2.size() = 2
画图:
画图如上,自我理解,有错误请指出。
总结
== 既可以比较基本类型也可以比较引用类型。对于基本类型就是比较值,对于引用类型就是比较内存地址
Equals的话,它是属于java.lang.Object类里面的方法,如果该方法没有被重写过默认也是==;我们可以看到String类的equals方法是被重写过的,而且String类在日常开发中用的比较多,久而久之,形成了equals是比较值的错误观点。
具体要看这有没有重写Object的hashCode方法和equals方法来判断。
2. equals 的重写
可以看出,重写equals,重写就要同时重写equals()和hashCode()。
当一个类有自己特有的“逻辑相等”概念,当改写equals()的时候,总是要改写hashCode(),根据一个类的equals方法(改写后),两个截然不同的实例有可能在逻辑上是相等的,但是,根据Object.hashCode方法,它们仅仅是两个对象。以Person为例,两个人都叫张三,但不是同一个人(equals),需要看的不是名字,而是身份证号码(hashCode)
因此,违反了“相等的对象必须具有相等的散列码”。
结论:复写equals方法的时候一般都需要同时复写hashCode方法。
3. 复写hashCode方法,31这个数字的作用
源码:
public int hashCode() {int h = hash;if (h == 0 && value.length > 0) {char val[] = value;for (int i = 0; i < value.length; i++) {h = 31 * h + val[i];}hash = h;}return h;}
计算机的乘法涉及到移位计算。当一个数乘以2时,就直接拿该数左移一位即可!选择31原因是因为31是一个素数。(素数:质数又称素数,在一个大于1的自然数中,除了1和此整数自身外,没法被其他自然数整除的数)
在存储数据计算hash地址的时候,我们希望尽量减少有同样的hash地址,所谓“冲突”。
因为任何数n * 31就可以被JVM优化为 (n << 5) -n,移位和减法的操作效率要比乘法的操作效率高的多,对左移虚拟机里面都有做相关优化,并且31只占用5bits。
Java基础之equals和==的区别深入解析相关推荐
- 程序猿的日常——Java基础之equals与hashCode
equals和hashCode是我们日常开发最常使用的方法,但是因为一般都使用默认的规则,因此也很少会引起关注.不过了解他们的用途和设计的原则,还是会帮助我们更好的设计代码. equals equal ...
- Java基础 抽象类和接口的区别、equals 与 == 的区别
一.抽象类和接口有什么区别 抽象类与接口都用于抽象,但是抽象类可以有自己的部分实现,而接口规范某一行为,调用者实现这个接口. 主要区别: 1.抽象类还是类只能单继承,而接口却可以多实现. 2.抽象类满 ...
- (面试)java基础-== 和 equals 的区别?
== 是比较栈帧中局部变量表的值,如果变量是基本数据类型,则栈内存中存放的就是具体数值,如果是引用类型,则栈中存放的是引用的内存地址. 所以对于基本数据类型,== 是比较值是否相等,对于引用数据类型, ...
- Java基础之equals方法和= =的区别
==操作符专门用来比较两个变量的值是否相等,也就是用于比较变量所对应的内存中所存储的数值是否相同,要比较两个基本类型的数据或两个引用变量是否相等,只能用==操作符. 如果一个变量指向的数据是对象类型的 ...
- java基础数据类型与String类型区别
区别:Java内存存放位置不一样,基本数据类型存在栈(stack),String的对象实例存在堆(heap).另外String,不是基本数据类型,判断是否相等,不能使用==,而应该使用equals方法 ...
- Java基础 - Integer和int的区别
一.int和Integer的区别 两者的区别主要体现在以下几个方面: 1.数据类型不同:int 是基础数据类型,而 Integer 是包装数据类型: 2.默认值不同:int 的默认值是 0,而 Int ...
- Java基础 ArrayList和LinkedList的区别和实现原理
ArrayList 和 LinkedList都是List的实现类,List集合主要有两个特点:1.有序:2.可重复.所以他们两个肯定也有其特征. 下面分别介绍下二者: 1.ArrayList--- ...
- java 的 == 和equals()区别
先看一个列子: public class Equivalence {public static void main(String[] args) {Integer n1 = new Integer(4 ...
- Java 基础——构造器和方法的区别
构造函数(构造器)是一种特殊的函数.其主要功能是用来在创建对象时初始化对象, 即为对象成员变量赋初始值,总与new运算符一起使用在创建对象的语句中.构造函数与类名相同,可重载多个不同的构造函数.在Ja ...
最新文章
- eclipse 源码设置UTF-8 (eclipse可以为JSP HTML 等各种文件不同编码格式设置) 在windows - preference- general-workspace
- 银行业应对信息安全威胁高危的三大原则
- 让input变成不可编辑状态的方法
- win7下安装pip——Python的包管理工具
- html5 canvas文字颜色,我可以通过HTML5 Canvas中的字符文本颜色来做吗?
- EF架构~codeFirst从初始化到数据库迁移
- input子系统基础之按键4——输入核心层源码分析
- eclipse报错Project facet Cloud Foundry Standalone Application version 1.0 is not supported.
- 树的平衡之AVL树——错过文末你会后悔,信我
- vscode+leetcode环境配置
- 阿里高德城市大脑·智慧交通战略发布,公共服务版首次亮相!
- 基础算法1——插入排序和希尔排序
- 微信打飞机java 源代码_微信打飞机
- android获取手机状态栏高度,Android 获取屏幕高度,宽度,状态栏高度
- 把PYTHON文件转换成exe的方法
- 3DGPS数据图和3D圆轨道图
- IBM新型Tivoli产品搭建绿色销售渠道
- 【企业管理】管理学十大原理
- Ribo-seq的下游分析方法1-ORFquant以及RiboQC
- python宣传视频 抖音_Python生成抖音字符视频,技术流!