基於基本型別對“==”和“equals()”的探究
首先宣告所有的探究都是基於jdk1.8.0_144版本上進行的。
開始之前我們先來看一段程式碼:
檢視程式碼
int x = 0;
double y = 0.0;
System.out.println(x == y);//true
System.out.println(Integer.hashCode(x));//0
System.out.println(Double.hashCode(y));//0
System.out.println(Objects.equals(x, y));//false
這裡我們聲明瞭兩個不同型別的變數,並且給他們賦了不同的值,可以用“==”進行判斷是發現返回的值是true,這個返回結果並不是我們所期待的,呼叫equals()方法返回的結果才是我們想看到的。同時,我們也看到了兩個變數他們的雜湊碼值是一樣的,這又是為什麼呢?
首先我們要知道java語言中是如何來給變數進行賦值的。
Double m = Double.valueOf(9.9);//包箱
double n = m.doubleValue();//拆箱
Integer x = Integer.valueOf(6);//包箱
int y = x.intValue();//拆箱
在Java中變數的賦值並不是我們所看到的那樣單純的將值賦給變數。每個基本資料型別Java中都會有一個對應的包裝類,每個類中呼叫.valueOf()就是對值進行自動包箱,呼叫.基本型別名Value()自動拆箱。下面我們來看一個例子:
檢視程式碼
System.out.println("==========Integer=========="); Integer a = new Integer(99); Integer b= new Integer(99); System.out.println(a == b);//false System.out.println(b.equals(a));//true Integer c = Integer.valueOf(99); Integer d = Integer.valueOf(99); System.out.println(c == d);//true System.out.println(c.equals(d));//true int e = c.intValue(); System.out.println(Integer.hashCode(e));//99 int f = d.intValue(); System.out.println(Integer.hashCode(f));//99 System.out.println(e == f);//true System.out.println(Objects.equals(e,f));//true
這裡我們先new了兩個Integer類。此時堆中會有兩個new的Integer類,用“==”進行判斷返回值是false,由此我們可以看到“==”是比較兩個物件的記憶體地址是否相同的。後面我們對資料進行Integer型別的包箱,此時用“==”進行判斷返回值是true。好,我們來看一下valueOf()方法:
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
這時候我們發現valueOf()方法中有一個IntegerCache的類:
檢視程式碼
private static class IntegerCache {
static final int low = -128;
static final int high;
static final Integer cache[];
static {
// high value may be configured by property
int h = 127;
String integerCacheHighPropValue =
sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
if (integerCacheHighPropValue != null) {
try {
int i = parseInt(integerCacheHighPropValue);
i = Math.max(i, 127);
// Maximum array size is Integer.MAX_VALUE
h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
} catch( NumberFormatException nfe) {
// If the property cannot be parsed into an int, ignore it.
}
}
high = h;
cache = new Integer[(high - low) + 1];
int j = low;
for(int k = 0; k < cache.length; k++)
cache[k] = new Integer(j++);
// range [-128, 127] must be interned (JLS7 5.1.7)
assert IntegerCache.high >= 127;
}
private IntegerCache() {}
}
/**
* Cache to support the object identity semantics of autoboxing for values between
* -128 and 127 (inclusive) as required by JLS.
*
* The cache is initialized on first usage. The size of the cache
* may be controlled by the {@code -XX:AutoBoxCacheMax=<size>} option.
* During VM initialization, java.lang.Integer.IntegerCache.high property
* may be set and saved in the private system properties in the
* sun.misc.VM class.
*/
通過註解可以知道這個快取池是存在一個範圍的下限是-128,上限是127(包含127)。快取在第一次使用是會被初始化,它的大小可能由AutoBoxCacheMax=<size>這個選項控制。此時,變數c,d都是存放快取中99所在的記憶體地址,因此"=="判斷返回的是true。
接下來我們來看equals()方法:
檢視程式碼
/**
* Compares this object to the specified object. The result is
* {@code true} if and only if the argument is not
* {@code null} and is an {@code Integer} object that
* contains the same {@code int} value as this object.
*
* @param obj the object to compare with.
* @return {@code true} if the objects are the same;
* {@code false} otherwise.
*/
public boolean equals(Object obj) {
if (obj instanceof Integer) {
return value == ((Integer)obj).intValue();
}
return false;
}
equals()比的是兩個物件的值,所以即使不是同一個物件,他們的值是相同的那麼返回的值也是true。
ok,我們Integer類講完了那我們來看看Doule類看看會有什麼不一樣呢?我先看一段程式碼:
檢視程式碼
System.out.println("==========Double==========");
Double j = new Double(123.0);
Double k = new Double(123.0);
System.out.println(j == k);//false
System.out.println(j.equals(k));//true
Double m = Double.valueOf(123);
Double n = Double.valueOf(123);
System.out.println(m == n);//false
System.out.println(m.equals(n));//true
System.out.println("------------------");
double x = m.doubleValue();
System.out.println(Double.hashCode(x));//1079951360
double y = n.doubleValue();
System.out.println(Double.hashCode(y));//1079951360
System.out.println("-------------------");
System.out.println(Objects.equals(x, y));//true
System.out.println(x == y);//true
如果按照前面Integer類的情況,我們呼叫完valueOf()方法後應該會初始化一個快取區,我們會從快取區中得到我們想到的資料,將資料在快取區中的記憶體地址賦值給變數。可是實際上並不是這樣的。
public static Double valueOf(double d) {
return new Double(d);
}
public Double(double value) {
this.value = value;
}
private final double value;
public double doubleValue() {
return value;
}
它會new一個新的Double類將資料進行包箱,所以“m==n”返回值是false,它沒有我們上面所講的快取區這一個說法。上面我們講了equals()是對於物件值的比較因此返回的是true;由於doubleValue()是直接返回Double類包箱的值,返回出x,y的hashCode()值發現他們的雜湊碼值是相同的即他們是同一個物件。所以“x==y”返回值也為true。