0
点赞
收藏
分享

微信扫一扫

“==“和equals的区别是什么(史上最全总结、最靠谱)


2021年了,奉上我最喜欢的一句话“愿你孤独的努力都有回报,愿你前行的路上有人陪伴”

编程是一个漫长的过程,一起加油,健康最重要,远离ICU😁

最近突然浏览到了一篇“==”和“equals”的区别,突然觉得自己应该深入理解一下它们之间的区别了(哈,不找理由了,菜是原罪😀)

相信只要你学过编程,那么“==”和equals你肯定使用过,除非是专精Hello World!的大佬。

“==“和equals的区别是什么(史上最全总结、最靠谱)_java

如果不查找资料你能回答出下面几个问题呢?

你知道“==”的使用场景吗?

你知道equals的使用场景吗?

你知道“==”和equals的区别在哪里吗?

你是否从底层探究过String以及包装类重写的equals代码?

上面几个问题,相信在座的大佬肯定都知道,那么请各位大佬阅读几分钟,帮我这个菜鸟纠正错误。

八股文来了

==:对于基本类型,比较的是值是否相等;对于引用类型,比较的是地址是否相等
equals:比较的是对象是否相等(不能比较基本类型,因为equals是Object超类中的方法,而Object是所有类的父类)

因为 Java 只有值传递,所以,对于 == 来说,不管是比较基本数据类型,还是引用数据类型的变量,其本质比较的都是值,只是引用类型变量存的值是对象的地址。
如果你不了解Java只有值传递,请看这篇文章:​​​带你深入理解值传递​​

==来了

看下面的例子

= new String("zsh");
String str2 = new String("zsh");
String str3 = "zsh";
String str4 = "zsh";
System.out.println(str3 == str4);
System.out.println(str == str2);
System.out.println(str == str3);

结果:

“==“和equals的区别是什么(史上最全总结、最靠谱)_字符串常量池_02

因为这是引用类型,所以比较的是地址是否相等,另外这也涉及到字符串常量池的概念,字符串常量池是什么呢,我怎么想不起来了呢?

“==“和equals的区别是什么(史上最全总结、最靠谱)_java_03


哈,我怎么可能是个小丑

当创建 String 类型的对象时,虚拟机会在常量池中查找有没有已经存在的值和要创建的值相同的对象,如果有就把它赋给当前引用。如果没有就在常量池中重新创建一个 String 对象。

字符串常量池简单了说就是一块内存空间,减少重复创建字符串所需的时间,更多细节请看我的JVM专栏

分析str3==str4的结果

1、这两个对象没有直接使用new,所以当执行String str3=“zsh”时,字符串常量池中就会被创建一个“zsh”的字符串;
2、当执行到String str4=“zsh”,会先去常量池中查找是否有“zsh”这个字符串,如果有,则将str4也指向这个字符串;否者在常量池中创建该字符串。

那么结果为true,自然就能够明白了。

分析str==str2的结果

这个为false应该也很简单,new两个对象,那么地址肯定不同;

分析str==str3的结果

一个是在字符串常量池中,一个在堆中new的对象,那么地址肯定不同了

“==“和equals的区别是什么(史上最全总结、最靠谱)_常量池_04


equals来了

= new String("zsh");
String str2 = new String("zsh");
String str3 = "zsh";
String str4 = "zsh";
System.out.println(str3.equals(str4));
System.out.println(str.equals(str2));
System.out.println(str.equals(str3));

“==“和equals的区别是什么(史上最全总结、最靠谱)_常量池_05


是不是感觉很奇怪,明明比较的是引用,为什么都是true呢?这就要分析String的底层代码了

public boolean equals(Object anObject) {
if (this == anObject) { //比较地址是否相等
return true;
}//判断是否是String类型,如果不是,还比较个锤子,肯定false呀
if (anObject instanceof String) {
//转换为本地变量
String anotherString = (String)anObject;
//计算字符长度,注意Java字符串末尾没有\0,因为对象都内置的有length方法,所以不需要计算长度。
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的区别是什么(史上最全总结、最靠谱)_java_06


这你应该就明白了,String中重写了Object中的equals方法,并重定义了它的功能,把它改成了比较字符串是否相同。

不仅String是这样,包装类也是同样如此

Integer

public boolean equals(Object obj) {
if (obj instanceof Integer) { //判断是否是Integer类型
return value == ((Integer)obj).intValue();//比较值是否相等
}
return false;
}

Float

public boolean equals(Object obj) {
return (obj instanceof Float)//是否满足是Float类型和值相等
&& (floatToIntBits(((Float)obj).value) == floatToIntBits(value));
}

Double

public boolean equals(Object obj) {
return (obj instanceof Double)
&& (doubleToLongBits(((Double)obj).value) ==
doubleToLongBits(value));
}

Boolean

public boolean equals(Object obj) {
if (obj instanceof Boolean) {
return value == ((Boolean)obj).booleanValue();
}
return false;
}

Character

public final boolean equals(Object obj) {
return (this == obj);
}

Long

public boolean equals(Object obj) {
if (obj instanceof Long) {
return value == ((Long)obj).longValue();
}
return false;
}

Boolean

public boolean equals(Object obj) {
if (obj instanceof Boolean) {
return value == ((Boolean)obj).booleanValue();
}
return false;
}

包装类全部都重写了equals方法,将其的地址比较改为了值比较。

= new User();
user.setUsername("zsh");
User user2 = new User();
user2.setUsername("zsh");
System.out.println(user.equals(user2));

结果:false

这个结果应该都在大家的意料之中,User类没重写equals方法,自然就按照地址比较了


举报

相关推荐

0 条评论