在進入正文之前 , 我們寫來看一段代碼
public static void main(String[] args) {
Integer i1 = 127;
Integer i2 = 127;
Integer i3 = new Integer(127);
System.out.println("one==:" + i1 == i2);
System.out.println("one2==:" + i1 == i3);
System.out.println("twoeq:"+i1.equals(i3));
System.out.println("threq:"+i1.equals(i2));
i1 = 128;
i2 = 128;
System.out.println("four==:" + i1 == i2);
System.out.println("fiveq:" + i1.equals(i2));
}
分析這段代碼 , 按照我們原來的想法 , 由於在比較對象爲基本數據類型時 , “==”比較的是值是否相等 , 但是 Integer 是 int 的包裝類 , 它是一個對象 , 所以 “==” 在這裏和 equals 一樣比較的是對象的引用是否相同 .
粗略一看 , 好像他們的輸出應該全爲 false , 因爲它們都創建了新的對象 .
的確 , 如果是其他對象的話 , 我們的猜想是沒有錯的 , 但是包裝類型不一樣 .
equals 在 包裝類型和 String 類中被重寫了 , 比較的是值是否相等
Object equals 方法實現如下:
public boolean eqauls(Object obj){
return (this == obj);
}
在包裝類型中重寫 :
public boolean equals(Object obj) {
if (obj instanceof Integer) {
return value == ((Integer)obj).intValue();
}
return false;
}
可以看到 , java 將 Object 幫我們轉換成了 Integer(對應包裝類) , 然後通過 Integer.intValue() 與 value(其值)使用 “==” 進行比較 , 結果自然而然是 true
接下來我們看看equals 在 String 中的重寫
public boolean equals(Object anObject) {
//如果引用相等
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String) anObject;
int n = value.length;
if (n == anotherString.value.length) {
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
//將 value 和 與之相比的 value 值拆分爲 char 一一比較
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}
因此我們對最開始的那段程序有了新的結論 , 他的輸出應該是
one==:false
one2==:false
twoeq:true
threq:true
four==:false
fiveq:true
如果這個時候你心滿意足 , 那恭喜你得不到正確答案了
包裝類型除了重寫了 equals , 在後臺還爲我們做了一件事情 – 緩存 !
java 爲了節省內存,設計了基本數據類型包裝類的緩存,就是程序啓動時,初始化的數值依次放在緩存池中,當你直接給 Integer 對象賦值時,它每次首先去緩存去查,如果有的話,直接將新 new 出的對象引用指向緩存池中的對象 ;
當然緩存池也不是無限大的 , Integer 緩存的範圍是[-128,127],超出範圍就需要重新在堆內存中new了,Byte 和 boolean 將全部緩存
所以我們運行最開始的程序的時候會發現 , 當 i1 , i2 爲 128 時 , 輸出的是 false
終於真相大白了 , 所以它最後的輸出應該是 :
one==:true //緩存
one2==:false // i3 爲新建對象 new Integer(127);
twoeq:true
threq:true
four==:false //超出緩存
fiveq:true
PS : java 雖然沒有對 String 做緩存 , 但是可以用 String.intern() 實現同樣效果