一直覺得自己Java基礎還不錯,但是第一眼看到(Integer)129 == (Integer)129表達式時竟然無法立刻反映過來結果到底是true還是false,不妨先來看一下下面簡單的Java程序:
package com.csdn.test;
public class Main {
public static void main(String[] args) {
System.out.println("(Integer)129 == (Integer)129");
System.out.println( (Integer)129 == (Integer)129);
System.out.println("(Integer)127 == (Integer)127");
System.out.println((Integer)127 == (Integer)127);
}
}
編譯運行後,控制檯輸出結果如下:
(Integer)129 == (Integer)129
false
(Integer)127 == (Integer)127
true
如果平時對Java基礎關注比較少,可能有兩三年經驗的Java程序員也沒辦法解釋爲什麼會有這種差異,筆者也是在網上查了一些資料才搞清楚來龍去脈。
要弄明白這個問題,首先要熟練掌握Java自動裝箱、拆箱相關的知識,Java中的自動裝/拆箱發生在運算操作和比較操作時,例如:
Integer a = 10;
a = a + 10; //1.拆箱爲int類型 2.計算 a+10 3.把20裝箱爲Integer類型.
System.out.print(a > 10); //1.把a拆箱爲int類型 2. 然後比較
使用==進行比較時,情況如下:
如果==兩邊都是裝箱類型,則比較引用是否指向堆內存中的同一個對象。
如過==兩邊有一邊是裝箱類型,另外一邊是基本類型,則把裝箱類型拆箱爲基本類型,然後進行比較。例如:
Integer a = new Integer(129);
Integer b = new Integer(129);
System.out.println(a == b); // 比較引用類型,返回false
System.out.println(a == 129); // a進行拆箱,基本類型比較,返回true
問題就在於,表達式(Integer)127 == (Integer)127和(Integer)129 == (Integer)129的值爲什麼不同呢?
我們不妨看一下java.lang.Integer類的源碼,如下:
/*
* Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved.
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*/
package java.lang;
import java.lang.annotation.Native;
/**
* The {@code Integer} class wraps a value of the primitive type
* {@code int} in an object. An object of type {@code Integer}
* contains a single field whose type is {@code int}.
*
* <p>In addition, this class provides several methods for converting
* an {@code int} to a {@code String} and a {@code String} to an
* {@code int}, as well as other constants and methods useful when
* dealing with an {@code int}.
*
* <p>Implementation note: The implementations of the "bit twiddling"
* methods (such as {@link #highestOneBit(int) highestOneBit} and
* {@link #numberOfTrailingZeros(int) numberOfTrailingZeros}) are
* based on material from Henry S. Warren, Jr.'s <i>Hacker's
* Delight</i>, (Addison Wesley, 2002).
*
* @author Lee Boynton
* @author Arthur van Hoff
* @author Josh Bloch
* @author Joseph D. Darcy
* @since JDK1.0
*/
public final class Integer extends Number implements Comparable<Integer> {
...
...
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() {}
}
...
...
}
這裏只截取了一部分關鍵代碼,如上面代碼所示,Integer類只對-128~127之間的對象做了緩存,(Integer)127 == (Integer)127兩邊裝箱後,實際指向堆內存中同一個對象,(Integer)129 == (Integer)129,裝箱爲引用類型後,沒有做緩存,指向堆內存中不同對象,所以比較結果爲false。