Java基礎系列-深入理解==和equals的區別(一)


一、前言

說到==和equals的問題,面試的時候可能經常被問題到,有時候如果你真的沒有搞清楚里邊的原因,被面試官一頓繞就懵了,所以今天我們也來徹底了解一下這個知識點。

二、==和equals的作用

2.1 ==的作用

在java中我們用==來判斷兩個變量是否相等,但是會根據數據類型有所區別:

1.對於8種基礎數據類型(byte、short、int、long、double、float、boolean、char)來說==是判斷變量的數值是否相等。

byte y1 = 1, y2 = 1;
short s1 = 1, s2 = 1;
int i1 = 1, i2 = 1;
long l1 = 1, l2 = 1;
double d1 = 1, d2 = 1;
float f1 = 1, f2 = 1;
boolean b1 = true, b2 = true;
char c1 = 1, c2 = 1;
System.out.println(
"byte:y1==y2 " + (y1 == y2)); System.out.println("short:s1==s2 " + (s1 == s2)); System.out.println("int:i1==i2 " + (i1 == i2)); System.out.println("long:l1==l2 " + (l1 == l2)); System.out.println("double:d1==d2 " + (d1 == d2)); System.out.println("float:f1==f2 " + (f1 == f2)); System.out.println("boolean:b1==b2 " + (b1 == b2)); System.out.println("char:c1==c2 " + (c1 == c2));

對於引用類型,==比較的是引用的地址是否相等:

 Object o1 = new Object();
 Object o2 = o1;
 Object o3 = new Object();
 System.out.println("Object:o1 == o2 " + (o1 == o2));
 System.out.println("Object:o1.equals(o2) " + (o1.equals(o2)));
 System.out.println("Object:o1 == o3 " + (o1 == o3));
 System.out.println("Object:o1.equals(o3) " + (o1.equals(o3)));

接下來我們來看看equals里的內部實現,其實還是調用的==:

總結:所以說對於==,當數據類型是8大基礎類型時,比較的是(棧中)數值是否相等,當數據類型是引用類型時,比較的是對象的引用地址是否相等。這是通過jvm來自動判斷的。

2.2 equals的作用

equals是object類中的一個方法,也就是說使用equals必須是對象類型,所以equals比較的是對象是否相當,默認情況上邊已經說過了使用的就是==,但是別忘了equals是基類中的方法,是可以重寫的,當我們重寫的時候就可以實現不同的功能了。

那么對於字符串,也是一種引用類型,我們先來看看下面這個例子:

String str1 = "123",str2 = "123";
String str3 = new String("123");
String str4 = new String("123");
System.out.println(
"String:str1 == str2 " + (str1 == str2)); System.out.println("Object:str1.equals(str2) " + (str1.equals(str2))); System.out.println("Object:str1 == str3 " + (str1 == str3)); System.out.println("Object:str1.equals(str3) " + (str1.equals(str3))); System.out.println("Object:str3 == str4 " + (str3 == str4)); System.out.println("Object:str3.equals(str4) " + (str3.equals(str4)));

這里我們介紹一個概念,叫做字符串拘留池:由於字符串這種東西在我們的程序中非常的常用,每一個字符串都要創建對象,花費開銷,但是通常字符串一般的我們只關心它的值是什么,所以jvm在這里做了一個優化,當字符串在拘留池(一塊存儲字符串的地方)里出現的時候,如果下次我們又用到了這個字符串,就直接返回池子里字符串的地址,因為值都是一樣的,減少了開銷,如果沒有,就放進池子里,以備后來有用到的時候,相當於一個緩存了。

所以當我們執行String str1 = "123",str2 = "123"; 實際上兩個變量指向的是同一個地址,所以自然的str1 == str2和str1.equals(str2)是一樣的,都為true,沒毛病。

當我們使用String str3 = new String("123");很明顯示開辟了一塊新的內存地址,只不過存儲的值是123是一樣的,所以str1 == str3是false,沒毛病,但是按理說str1.equals(str3)也應該是false啊,之前不是說內部也是用的==嗎,我們可以看一下字符串類中equals的實現:

很明顯,在實現判斷了地址是否相同以后,這里邊又做了判斷,字符串的值是否相等,如果相等就返回true,到這里為止,我們已經真相大白了,原來String類重寫equals方法,判斷的是字符串的值是否相等,而不僅僅是地址。所以自然的我們的str1.equals(str3) 是true了。

那么由此可知,str3 == str4 比較的是地址,明顯不一樣,因為是new了兩個對象,所以返回false,str3.equals(str4)比較的是字符串的值,所以返回true,也沒毛病。

總結:因為我們在對字符串比較的時候,往往關注的就是值一樣不一樣,所以java這樣重寫也是 很有必要的,所以我們一直推薦判斷字符串相等用equals方法,而不是用==來判斷。equals方法具體產生什么樣的效果,完全看子類是怎么重寫的,比如Date類,重寫了equals方法,只要兩個時間的getTime()時間戳一樣,那么就相等,這也是符合我們的認知的。

所以,在我們以后需要判斷兩個對象相等的用equals的時候,我們可以完全根據自己的業務來重寫equals方法,比如兩個Person實例,如果id一樣,我們就應該認為他們倆是相等,這個時候我們就可以重寫equals方法,用id作比較來返回值。

三、總結

這次終於搞明白了==和equals的用法和作用,以后學什么東西還必須要深入理解一下內部原理才行,這樣就不怕面試官再來搞事情了。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM