之前在IDEA中引入了阿里巴巴的Java規範插件,自動檢測了一下開發中的項目,發現很多“不規範”的“常規”代碼。然而,往往被我們忽視的常見代碼,會隱藏着不規範的漏洞。
相信剛入職的Java開發者都遇到過這樣的面試題:“說一下Java中==和equals的區別”。
我們先來複習一下,Java中的基本數據類型。
Java中基本數據類型
上述Java中八種基本數據類型,對應的包裝類型分別爲:Boolean、Byte、Character、Short、Integer、Long、Float、Double。
將基本數據類型封裝成對象的好處在於可以在對象中定義更多的功能方法操作該數據。
包裝類之間相等判斷的正確方式
- 包裝類型間的相等判斷應該用equals,而不是“==”;
- 原因分析:
包裝類型間的相等判斷應該用equals,而不是’==’。
說明:對於Integer var=?在-128至127之間的賦值,Integer對象是在IntegerCache.cache產生,會複用已有對象,這個區間內的Integer值可以直接使用==進行判斷,但是這個區間之外的所有數據,都會在堆上產生,並不會複用已有對象,這是一個大坑,推薦使用equals方法進行判斷。
- 示例:
public class EqualsTest {
public static void main(String[] args) {
Integer a0 = 256;
Integer b0 = 256;
// 結果輸出false:包裝類型的相等比較應該用equals
// Integer範圍:-128~127
System.out.println(a0==b0);
Integer a1 = -128;
Integer b1 = -128;
// 結果輸出true:包裝類型的相等比較應該用equals
// Integer範圍:-128~127
System.out.println(a1==b1);
}
}
- 分析:
上述定義變量a0、b0等,實際體現在Integer源碼中是調用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範圍內,直接取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,在這個範圍內的對象,直接從cache[],Integer常量池中獲取。
如果想控制範圍大小,則需要通過-XX:AutoBoxCacheMax=設置。
我們進一步查看一下JDK中Integer源碼中equals方法:
public boolean equals(Object obj) {
if (obj instanceof Integer) {
return value == ((Integer)obj).intValue();
}
return false;
}
可見,Integer重寫了equals方法,通過equals比較的是Integer包裝類的int值。
-
附:
所有整數類型的類都有類似的緩存機制:
Byte 有 ByteCache 用於緩存 Byte 對象;
Short 有 ShortCache 用於緩存 Short 對象;
Long 有 LongCache 用於緩存 Long 對象。
Byte,Short,Long 的緩存池範圍默認都是: -128 到 127。 -
在日常項目開發中,我們往往喜歡使用==進行比較,因爲日常開發中封裝在實體類中的數值通常範圍都在-128-127範圍之內,所以基本沒出現過異常,但是爲了更好、更規範、更嚴謹的使用Java,還是需要使用equals比較。
總結:
1.==的比較(基本數據類型,比較的是值是否相等;非基本數據類型,即引用類型,比較的是對象指向的內存地址是否一致,即同一對象。)
2.而equals的比較(如果沒有對equals方法進行重寫,則比較的是引用類型的變量所指向的對象的地址;包裝類型中分別都對equals方法進行了重寫,只比較值是否相等。)
PS:
歡迎關注微信公衆號:程序員說事兒
更多Java技術分享!一起成長!