概述
這幾天,被幾道java基礎(chǔ)練習(xí)題中的==和equals給繞暈了进栽,所以打算把關(guān)于這塊的內(nèi)容好好總結(jié)下德挣,爭取下次再遇到類似的題目,自己不會(huì)再出錯(cuò)快毛,恩格嗅,就是這樣。
簡單了解
在Object類中唠帝,equals方法的定義是這樣的屯掖,
public boolean equals(Object obj)
{
return (this == obj);
}
這塊就有點(diǎn)懵了,這不還是用==來進(jìn)行比較的嗎襟衰?再往下搜了才知道贴铜,在大部分的封裝類中,都重寫了Object類的這個(gè)方法瀑晒,所以兩者還是會(huì)有區(qū)別的绍坝。總的來說苔悦,==是一個(gè)關(guān)系運(yùn)算符轩褐,如果比較的兩端都為基本類型,則判斷兩者的值是否相等,(判斷過程中還有不同基本類型的轉(zhuǎn)化间坐,這里不做討論)灾挨,如果比較的兩端都為引用類型的話,則比較兩者所指向?qū)ο蟮牡刂肥欠裣嗤袼危粚τ趀quals方法劳澄,首先,能調(diào)用這個(gè)方法肯定是一個(gè)對象蜈七,然后秒拔,如果這個(gè)對象所在的類重寫了equals方法,則按照重寫的方法進(jìn)行比較飒硅,如果沒有砂缩,則比較兩者所指向?qū)ο蟮牡刂肥欠裣嗤?/p>
自己動(dòng)手
了解了上面那么多內(nèi)容之后作谚,然后自己就寫了一個(gè)小小的測試程序,打算驗(yàn)證下庵芭,代碼如下:
1.public class Test{
2. public static void main(String[] args) {
3. Integer a = new Integer(200);
4. Integer b = new Integer(200);
5. Integer c = 200;
6. Integer e = 200;
7. int d = 200;
8.
9. System.out.println("兩個(gè)new出來的對象 ==判斷"+(a==b));
10. System.out.println("兩個(gè)new出來的對象 equal判斷"+a.equals(b));
11. System.out.println("new出的對象和用int賦值的Integer ==判斷"+(a==c));
12. System.out.println("new出的對象和用int賦值的Integer equal判斷"+(a.equals(c)));
13. System.out.println("兩個(gè)用int賦值的Integer ==判斷"+(c==e));
14. System.out.println("兩個(gè)用int賦值的Integer equal判斷"+(c.equals(e)));
15. System.out.println("基本類型和new出的對象 ==判斷"+(d==a));
16. System.out.println("基本類型和new出的對象 equal判斷"+(a.equals(d)));
17. System.out.println("基本類型和自動(dòng)裝箱的對象 ==判斷"+(d==c));
18. System.out.println("基本類型和自動(dòng)裝箱的對象 equal判斷"+(c.equals(d)));
19. }
20.}
執(zhí)行的結(jié)果如下
兩個(gè)new出來的對象 ==判斷false
兩個(gè)new出來的對象 equal判斷true
new出的對象和用int賦值的Integer ==判斷false
new出的對象和用int賦值的Integer equal判斷true
兩個(gè)用int賦值的Integer ==判斷false
兩個(gè)用int賦值的Integer equal判斷true
基本類型和new出的對象 ==判斷true
基本類型和new出的對象 equal判斷true
基本類型和自動(dòng)裝箱的對象 ==判斷true
基本類型和自動(dòng)裝箱的對象 equal判斷true
首先妹懒,第9行中,對于兩個(gè)new出來的Integer對象双吆,用==比較兩者眨唬,得到了false,這點(diǎn)應(yīng)該挺好理解的好乐,每次使用new關(guān)鍵字匾竿,都會(huì)在堆內(nèi)存中申請一塊空間,存放相應(yīng)的對象的值蔚万,然后在棧中存放這塊內(nèi)存的引用岭妖。而==運(yùn)算符比較兩者所指向?qū)ο蟮牡刂肥欠裣嗤暾埩藘蓧K空間反璃,地址肯定不相同昵慌,所以結(jié)果為false。
第10行中版扩,結(jié)果為true废离,查了下java的源碼侄泽,發(fā)現(xiàn)Integer重寫的equals方法是這樣的:
public boolean equals(Object obj) {
if (obj instanceof Integer) {
return value == ((Integer)obj).intValue();
}
return false;
}
又調(diào)用了一個(gè)intValue方法礁芦,它的實(shí)現(xiàn)是這樣的:
public int intValue()
{
return value;
}
首先判斷傳進(jìn)來的Object類型是不是Integer類的一個(gè)實(shí)例,如果不是直接返回false悼尾;如果是則判斷兩者的成員變量value值是不是相等的(Integer類中定義的private final int value)柿扣,這塊又回到了基本類型的比較。value的值在創(chuàng)建這個(gè)對象的時(shí)候被賦值闺魏,兩個(gè)Integer對象傳遞的參數(shù)都為200未状,所以value值相等,返回true析桥。
看第11行前司草,先看下第5行。第5行中泡仗,用int給Integer賦值的那條語句埋虹,從jdk1.5開始能這么做了,因?yàn)閺倪@個(gè)版本開始娩怎,java引入了自動(dòng)裝箱搔课、自動(dòng)拆箱機(jī)制。第5行就是一個(gè)自動(dòng)裝箱的過程截亦,相當(dāng)于:
Integer c = Integer.valueOf(200);
在Integer類中爬泥,valueOf方法是這么實(shí)現(xiàn)的:
public static Integer valueOf(int i) {
assert IntegerCache.high >= 127;
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
上面這段代碼首先規(guī)定了一個(gè)范圍柬讨,默認(rèn)是-128-127之間,如果參數(shù)中的i在這個(gè)范圍之內(nèi)袍啡,則返回一個(gè)數(shù)組中的內(nèi)容踩官,如果不在這個(gè)范圍,則new一個(gè)新的Integer對象并返回境输。查看Integer類的源碼可以發(fā)現(xiàn)卖鲤,這個(gè)數(shù)組里面緩存了基本類型-128-127之間的Integer對象。但是由于第11行是與一個(gè)new出來的對象做比較畴嘶,所以==肯定返回的false蛋逾。
第12行,equals方法比較兩個(gè)對象的value值窗悯,所以為true区匣。
第13行,兩個(gè)自動(dòng)裝箱的變量蒋院,但是裝箱傳遞的值大于127亏钩,所以返回false。這這塊又試了下在-128到127之間的數(shù)欺旧,結(jié)果為true姑丑,大家可以試下。
第14行辞友,結(jié)果為true栅哀。兩個(gè)自動(dòng)裝箱的Integer對象,比較value称龙。
第15行留拾,這塊進(jìn)行比較的時(shí)候,會(huì)對Integer對象進(jìn)行自動(dòng)拆箱鲫尊,也就是調(diào)用intValue方法痴柔,方法如上。兩個(gè)基本數(shù)據(jù)類型進(jìn)行==判斷疫向,根據(jù)值比較咳蔚,所以結(jié)果為true。這塊可能有人會(huì)問搔驼,為什么不是對int類型進(jìn)行自動(dòng)裝箱處理呢谈火?其實(shí)這塊是java根據(jù)一個(gè)很明顯的道理進(jìn)行設(shè)計(jì)的:如果有人比較一個(gè)int類型的值和Integer類型的值,是想比較什么呢匙奴?肯定是值呀堆巧,所以這塊是對Integer對象進(jìn)行拆箱而不是對int類型裝箱了。
第16行這塊,首先調(diào)用equals方法的肯定是Integer對象谍肤,但是Integer類中重寫的equals方法參數(shù)是一個(gè)Object類型呀啦租,怎么能傳遞一個(gè)基本數(shù)據(jù)類型進(jìn)去呢?所以荒揣,這塊又是一個(gè)自動(dòng)裝箱的表現(xiàn)篷角,當(dāng)傳遞一個(gè)int類型給equals這個(gè)方法時(shí),java會(huì)自動(dòng)將這個(gè)值打包裝箱為Integer類系任,而Integer類的最終父類又是Object恳蹲,所以這塊參數(shù)的問題就解決了,然后就是兩個(gè)Integer對象進(jìn)行equals判斷俩滥,返回true嘉蕾。
第17行,首先d為一個(gè)基本類型int霜旧,c為一個(gè)Integer對象错忱,所以進(jìn)行==比較的時(shí)候,肯定會(huì)對Integer對象進(jìn)行拆箱處理挂据,所以結(jié)果為true以清。
第18行,同第16行崎逃。
總結(jié)
“==比較地址掷倔,equals比較值”這個(gè)還是挺靠譜的。但是對于包裝類和基本類型个绍,還要涉及它們的自動(dòng)裝箱勒葱、自動(dòng)拆箱,所以小心一點(diǎn)還是比較好的障贸,不要走到別人挖的陷阱中错森。