java基礎中Integer值用==和equals判斷相等問題解析

問題描述:

定義了兩個Integer變量,爲Integer a= 200;  Integer b= 200; ,  但我比較的時候 if (a == b),卻返回false,不都是200嗎?爲什麼返回false,後來改爲equals(),返回true,這其中的端倪,且聽我下面分析:

在Object類中,equals方法的定義是這樣的,

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

看到這塊,懵了,這不還是用==來進行比較的嗎?

原因分析:在大部分的封裝類中,都重寫了Object類的這個方法,所以兩者還是會有區別的。總的來說,==是一個關係運算符,如果比較的兩端都爲基本類型,則判斷兩者的值是否相等,(判斷過程中還有不同基本類型的轉化,這裏不做討論),如果比較的兩端都爲引用類型的話,則比較兩者所指向對象的地址是否相同;對於equals方法,首先,能調用這個方法肯定是一個對象,然後,如果這個對象所在的類重寫了equals方法,則按照重寫的方法進行比較,如果沒有,則比較兩者所指向對象的地址是否相同。


接下來就自己動手寫測試程序驗證,代碼如下:

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("兩個new出來的對象    ==判斷"+(a==b));
10.        System.out.println("兩個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("兩個用int賦值的Integer    ==判斷"+(c==e));
14.        System.out.println("兩個用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==c));
18.        System.out.println("基本類型和自動裝箱的對象   equal判斷"+(c.equals(d)));
19.    }
20.}

執行的結果如下:

兩個new出來的對象    ==判斷false
兩個new出來的對象    equal判斷true
new出的對象和用int賦值的Integer   ==判斷false
new出的對象和用int賦值的Integer   equal判斷true
兩個用int賦值的Integer    ==判斷false
兩個用int賦值的Integer    equal判斷true
基本類型和new出的對象   ==判斷true
基本類型和new出的對象   equal判斷true
基本類型和自動裝箱的對象   ==判斷true
基本類型和自動裝箱的對象   equal判斷true


首先,第9行中,對於兩個new出來的Integer對象,用==比較兩者,得到了false,原因分析如下:

每次使用new關鍵字,都會在堆內存中申請一塊空間,存放相應的對象的值,然後在棧中存放這塊內存的引用地址。而==運算符比較兩者所指向對象的地址是否相同,申請了兩塊空間,地址肯定不相同,所以結果爲false。


第10行中,結果爲true,我們先
查看一下java的源碼,發現Integer重寫了equals方法如下:

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

由上面的源碼可知,equals方法又調用了一個intValue方法,繼續查看intValue方法源碼:

public int intValue()  
{  
  return value;  
}

看完源碼,我們分析一下:

首先,判斷傳進來的Object類型是不是Integer類的一個實例,如果不是直接返回false;

如果是則判斷兩者的成員變量value值是不是相等的(Integer類中定義的private final int value),這塊又回到了基本類型的比較。value的值在創建這個對象的時候被賦值,兩個Integer對象傳遞的參數都爲200,所以value值相等,返回true。


看第11行前,先看下第5行。第5行中,用int給Integer賦值的那條語句,從jdk1.5開始能這麼做了,因爲從這個版本開始,java引入了自動裝箱、自動拆箱機制。第5行就是一個自動裝箱的過程,相當於:
Integer c = Integer.valueOf(200);
在Integer類中,valueOf方法是這麼實現的:

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);  
}

上面這段代碼首先規定了一個範圍,默認IntegerCache.low 是-127,Integer.high是128,如果參數中的i在這個範圍之內,則返回一個數組中的內容,如果不在這個範圍,則new一個新的Integer對象並返回。查看Integer類的源碼可以發現,這個數組裏面緩存了基本類型-128-127之間的Integer對象。但是由於第11行是與一個new出來的對象做比較,所以==肯定返回的false。
第12行,equals方法比較兩個對象的value值,所以爲true。
第13行,兩個自動裝箱的變量,但是裝箱傳遞的值大於127,所以返回false。這這塊又試了下在-128到127之間的數,結果爲true,大家可以試下。
第14行,結果爲true。兩個自動裝箱的Integer對象,比較value。
第15行,這塊進行比較的時候,會對Integer對象進行自動拆箱,也就是調用intValue方法,方法如上。兩個基本數據類型進行==判斷,根據值比較,所以結果爲true。這塊可能有人會問,爲什麼不是對int類型進行自動裝箱處理呢?其實這塊是java根據一個很明顯的道理進行設計的:如果有人比較一個int類型的值和Integer類型的值,是想比較什麼呢?肯定是值呀,所以這塊是對Integer對象進行拆箱而不是對int類型裝箱了。
第16行這塊,首先調用equals方法的肯定是Integer對象,但是Integer類中重寫的equals方法參數是一個Object類型呀,怎麼能傳遞一個基本數據類型進去呢?所以,這塊又是一個自動裝箱的表現,當傳遞一個int類型給equals這個方法時,java會自動將這個值打包裝箱爲Integer類,而Integer類的最終父類又是Object,所以這塊參數的問題就解決了,然後就是兩個Integer對象進行equals判斷,返回true。
第17行,首先d爲一個基本類型int,c爲一個Integer對象,所以進行==比較的時候,肯定會對Integer對象進行拆箱處理,所以結果爲true。
第18行,同第16行。

總結

“==比較地址,equals比較值”這個還是挺靠譜的。但是對於包裝類和基本類型,還要涉及它們的自動裝箱、自動拆箱,所以小心一點還是比較好的,尤其是在以後的面試中,不要走到別人挖的陷阱中。

1. Integer 類型的值在[-128,127] 期間,Integer 用 “==”是可以的   , Integer  與 int 類型比較(==)比較的是值。

2. 如果要比較Integer的值,比較靠譜的是通過Integer.intValue();這樣出來的就是int值,就可以直接比較了;或者equals()比較




發佈了10 篇原創文章 · 獲贊 25 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章