
之前在IDEA中引入了阿里巴巴的Java規(guī)范插件,自動檢測了一下開發(fā)中的項目,發(fā)現(xiàn)很多“不規(guī)范”的“常規(guī)”代碼。然而,往往被我們忽視的常見代碼,會隱藏著不規(guī)范的漏洞。
相信剛?cè)肼毜腏ava開發(fā)者都遇到過這樣的面試題:“說一下Java中==和equals的區(qū)別”。
我們先來復(fù)習(xí)一下,Java中的基本數(shù)據(jù)類型
Java中基本數(shù)據(jù)類型

上述Java中八種基本數(shù)據(jù)類型,對應(yīng)的包裝類型分別為:Boolean、Byte、Character、Short、Integer、Long、Float、Double。
將基本數(shù)據(jù)類型封裝成對象的好處在于可以在對象中定義更多的功能方法操作該數(shù)據(jù)。
包裝類之間相等判斷的正確方式
-
包裝類型間的相等判斷應(yīng)該用equals,而不是“==”;
警告提示.png -
原因分析:
原因.png
包裝類型間的相等判斷應(yīng)該用equals,而不是'=='。
說明:對于Integer var=?在-128至127之間的賦值,Integer對象是在IntegerCache.cache產(chǎn)生,會復(fù)用已有對象,這個區(qū)間內(nèi)的Integer值可以直接使用==進行判斷,但是這個區(qū)間之外的所有數(shù)據(jù),都會在堆上產(chǎn)生,并不會復(fù)用已有對象,這是一個大坑,推薦使用equals方法進行判斷。
- 示例:
public class EqualsTest {
public static void main(String[] args) {
Integer a0 = 256;
Integer b0 = 256;
// 結(jié)果輸出false:包裝類型的相等比較應(yīng)該用equals
// Integer范圍:-128~127
System.out.println(a0==b0);
Integer a1 = -128;
Integer b1 = -128;
// 結(jié)果輸出true:包裝類型的相等比較應(yīng)該用equals
// Integer范圍:-128~127
System.out.println(a1==b1);
}
}
- 分析:
上述定義變量a0、b0等,實際體現(xiàn)在Integer源碼中是調(diào)用valueOf(int i)方法
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
可見,當i的值在low和high范圍內(nèi),直接取IntegerCache.cache的常量池中得對象。如果在范圍之外,則直接new一個Integer新的對象。
查看一下Integer源碼中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.
*/
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() {}
}
可見,IntegerCache中范圍為-128到127,在這個范圍內(nèi)的對象,直接從cache[],Integer常量池中獲取。
如果想控制范圍大小,則需要通過-XX:AutoBoxCacheMax=<size>設(shè)置。
我們進一步查看一下JDK中Integer源碼中equals方法:
public boolean equals(Object obj) {
if (obj instanceof Integer) {
return value == ((Integer)obj).intValue();
}
return false;
}
可見,Integer重寫了equals方法,通過equals比較的是Integer包裝類的int值。
附:
所有整數(shù)類型的類都有類似的緩存機制:
Byte 有 ByteCache 用于緩存 Byte 對象;
Short 有 ShortCache 用于緩存 Short 對象;
Long 有 LongCache 用于緩存 Long 對象。
Byte,Short,Long 的緩存池范圍默認都是: -128 到 127。在日常項目開發(fā)中,我們往往喜歡使用==進行比較,因為日常開發(fā)中封裝在實體類中的數(shù)值通常范圍都在-128-127范圍之內(nèi),所以基本沒出現(xiàn)過異常,但是為了更好、更規(guī)范、更嚴謹?shù)氖褂肑ava,還是需要使用equals比較。
總結(jié):
1.==的比較(基本數(shù)據(jù)類型,比較的是值是否相等;非基本數(shù)據(jù)類型,即引用類型,比較的是對象指向的內(nèi)存地址是否一致,即同一對象。)
2.而equals的比較(如果沒有對equals方法進行重寫,則比較的是引用類型的變量所指向的對象的地址;包裝類型中分別都對equals方法進行了重寫,只比較值是否相等。)

