1. 程式人生 > >Java基礎系列-深入理解==和equals的區別(一)

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的用法和作用,以後學什麼東西還必須要深入理解一下內部原理才行,這樣就不怕面試官再來搞事情