Java基础之equals和==的区别深入解析


以下是本文目录大纲

  1. equals 和 == 的区别
  2. equals 的重写
  3. 复写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

画图:


画图如上,自我理解,有错误请指出。


总结
  1. == 既可以比较基本类型也可以比较引用类型。对于基本类型就是比较值,对于引用类型就是比较内存地址

  2. Equals的话,它是属于java.lang.Object类里面的方法,如果该方法没有被重写过默认也是==;我们可以看到String类的equals方法是被重写过的,而且String类在日常开发中用的比较多,久而久之,形成了equals是比较值的错误观点。

  3. 具体要看这有没有重写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和==的区别深入解析相关推荐

  1. 程序猿的日常——Java基础之equals与hashCode

    equals和hashCode是我们日常开发最常使用的方法,但是因为一般都使用默认的规则,因此也很少会引起关注.不过了解他们的用途和设计的原则,还是会帮助我们更好的设计代码. equals equal ...

  2. Java基础 抽象类和接口的区别、equals 与 == 的区别

    一.抽象类和接口有什么区别 抽象类与接口都用于抽象,但是抽象类可以有自己的部分实现,而接口规范某一行为,调用者实现这个接口. 主要区别: 1.抽象类还是类只能单继承,而接口却可以多实现. 2.抽象类满 ...

  3. (面试)java基础-== 和 equals 的区别?

    == 是比较栈帧中局部变量表的值,如果变量是基本数据类型,则栈内存中存放的就是具体数值,如果是引用类型,则栈中存放的是引用的内存地址. 所以对于基本数据类型,== 是比较值是否相等,对于引用数据类型, ...

  4. Java基础之equals方法和= =的区别

    ==操作符专门用来比较两个变量的值是否相等,也就是用于比较变量所对应的内存中所存储的数值是否相同,要比较两个基本类型的数据或两个引用变量是否相等,只能用==操作符. 如果一个变量指向的数据是对象类型的 ...

  5. java基础数据类型与String类型区别

    区别:Java内存存放位置不一样,基本数据类型存在栈(stack),String的对象实例存在堆(heap).另外String,不是基本数据类型,判断是否相等,不能使用==,而应该使用equals方法 ...

  6. Java基础 - Integer和int的区别

    一.int和Integer的区别 两者的区别主要体现在以下几个方面: 1.数据类型不同:int 是基础数据类型,而 Integer 是包装数据类型: 2.默认值不同:int 的默认值是 0,而 Int ...

  7. Java基础 ArrayList和LinkedList的区别和实现原理

    ArrayList 和 LinkedList都是List的实现类,List集合主要有两个特点:1.有序:2.可重复.所以他们两个肯定也有其特征. 下面分别介绍下二者:  1.ArrayList---  ...

  8. java 的 == 和equals()区别

    先看一个列子: public class Equivalence {public static void main(String[] args) {Integer n1 = new Integer(4 ...

  9. Java 基础——构造器和方法的区别

    构造函数(构造器)是一种特殊的函数.其主要功能是用来在创建对象时初始化对象, 即为对象成员变量赋初始值,总与new运算符一起使用在创建对象的语句中.构造函数与类名相同,可重载多个不同的构造函数.在Ja ...

最新文章

  1. eclipse 源码设置UTF-8 (eclipse可以为JSP HTML 等各种文件不同编码格式设置) 在windows - preference- general-workspace
  2. 银行业应对信息安全威胁高危的三大原则
  3. 让input变成不可编辑状态的方法
  4. win7下安装pip——Python的包管理工具
  5. html5 canvas文字颜色,我可以通过HTML5 Canvas中的字符文本颜色来做吗?
  6. EF架构~codeFirst从初始化到数据库迁移
  7. input子系统基础之按键4——输入核心层源码分析
  8. eclipse报错Project facet Cloud Foundry Standalone Application version 1.0 is not supported.
  9. 树的平衡之AVL树——错过文末你会后悔,信我
  10. vscode+leetcode环境配置
  11. 阿里高德城市大脑·智慧交通战略发布,公共服务版首次亮相!
  12. 基础算法1——插入排序和希尔排序
  13. 微信打飞机java 源代码_微信打飞机
  14. android获取手机状态栏高度,Android 获取屏幕高度,宽度,状态栏高度
  15. 把PYTHON文件转换成exe的方法
  16. 3DGPS数据图和3D圆轨道图
  17. IBM新型Tivoli产品搭建绿色销售渠道
  18. 【企业管理】管理学十大原理
  19. Ribo-seq的下游分析方法1-ORFquant以及RiboQC
  20. python宣传视频 抖音_Python生成抖音字符视频,技术流!

热门文章

  1. 企业如何走出自己的CRM非常之道?
  2. 【网络知识点】防火墙主备冗余技术
  3. MQTT协议笔记之mqtt.io项目TCP协议支持
  4. error Infos
  5. Android 条码扫描程序源码
  6. 2021牛客多校5 - Double Strings(dp+组合数学)
  7. linux排序语言,Go语言排序sort的使用
  8. PTA-习题11-2 查找星期 (15 分)-enum
  9. python3爬虫(9)分布式爬虫与对等分布式爬虫
  10. 关于SOCKET中send和recv函数工作原理总结