java程序中測試兩個變量是否相等有兩種方式,一種是利用==運算符,一種是利用equals()方法。
(1)“==”
==是判斷的意思,對於局部變量的基本類型(byte,short,int,long,float,double,char,boolean)存儲在棧之中,比較的是值,只要值相等,就返回True
int i=0;
double x=0.00;
System.out.println(i==x); // true
而對於引用類型來說,它比較的是變量(棧)內存中存放的對象的(堆)內存地址,用來判斷兩個對象的地址是否相同,即是否是指相同一個對象。
String i=new String("x");
String n=new String("x");
System.out.println(i==n); // false
在舉個例子,對於在常量池的變量來說,又有新情況
String s3="hello";
String s4="hello";
System.out.println(s3==s4); // true
這是因爲hello已經在常量池中了,s4只是重新指向了它,並沒有新建一個對象,所以也就沒有對象地址不同的情況了
(2)“equals”
其用於比較對象的地址,所以其對引用類型的比較和==的作用相同
源碼
基礎版
public boolean equals(Object obj) {
return (this == obj);
}
分析:從源碼可以看出,一般情況下,equals和==是等價的
一般引用的equals
對於Integer、Boolean等封裝類來說,重寫了equals
源碼如下
(注: instaninstanceof是指,前面的對象是否是後面類的引用)
public boolean equals(Object obj) {
if (obj instanceof Integer) {
return value == ((Integer)obj).intValue();
}
return false;
}
public boolean equals(Object obj) {
if (obj instanceof Boolean) {
return value == ((Boolean)obj).booleanValue();
}
return false;
}
分析:雖然增加了一個判斷,但實質上仍然是==的比較
String字符串的equals
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;
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}
分析:這個代碼的意思是,如果兩個對象==成立,那麼就返回true,如果對象中有String,那麼就會一個字符一個字符的比較,判斷字符串中每個字符是否相同。
equals擴展
對於equals,jdk給出了一些解釋
equals方法在非空對象引用上實現等價關係:
- 自反性 :對於任何非空的參考值x , x.equals(x)應該返回true 。
- 它是對稱的 :對於任何非空引用值x和y , x.equals(y)應該返回true當且僅當y.equals(x)回報true 。
- 傳遞性 :對於任何非空引用值x , y和z ,如果x.equals(y)回報true個y.equals(z)回報true ,然後x.equals(z)應該返回true 。
- 它是一致的 :對於任何非空引用值x和y ,多次調用x.equals(y)始終返回true或始終返回false ,沒有設置中使用的信息equals比較上的對象被修改。
- 對於任何非空的參考值x , x.equals(null)應該返回false 。
還有需要注意的:
該equals類方法Object實現對象上差別可能性最大的相等關係; 也就是說,對於任何非空的參考值x和y ,當且僅當x和y引用相同的對象( x == y具有值true )時,該方法返回true 。
請注意,無論何時覆蓋該方法,通常需要覆蓋hashCode方法,以便維護hashCode方法的通用合同,該方法規定相等的對象必須具有相等的哈希碼。
equals和hashcode
equals相等就一定有一樣的hashcode,hashcode一樣,equals不一定返回true
簡單解釋hashcode
對於JVM虛擬機來說,在堆中有很多很多的對象,那麼如何去尋找他們,難道從頭遍歷嗎?JVM選擇使用一張表來記錄各個對象的位置,一般由哈希編碼來記錄,每個哈希編碼是獨一無二的,可以根據哈希編碼找到對象地址(也有極少數特殊情況暫不贅述)
hashcode方法在object中定義
public native int hashCode();
native 關鍵字也就說明了這個方法的底層不由Java來實現,該方法會返回object的整型數字
hashcode能大大降低對象比較次數,提高查找效率!
解釋: equals相等就一定有一樣的hashcode,hashcode一樣,equals不一定返回true
如果兩個Java對象A和B,A和B相等(eqauls結果爲true),但A和B的哈希碼不同,則A和B存入HashMap時的哈希碼計算得到的HashMap內部數組位置索引可能不同,那麼A和B很有可能允許同時存入HashMap,顯然相等/相同的元素是不允許同時存入HashMap,HashMap不允許存放重複元素。
假如兩個Java對象A和B,A和B不相等(eqauls結果爲false),但A和B的哈希碼相等,將A和B都存入HashMap時會發生哈希衝突,也就是A和B存放在HashMap內部數組的位置索引相同這時HashMap會在該位置建立一個鏈接表,將A和B串起來放在該位置,顯然,該情況不違反HashMap的使用原則,是允許的。
舉個例子
1 String str1 = "通話";
2 String str2 = "重地";
3 System.out.println(String.format("str1:%d | str2:%d", str1.hashCode(),str2.hashCode()));
4 System.out.println(str1.equals(str2));
執行的結果:
str1:1179395 | str2:1179395
false
很顯然“通話”和“重地”的 hashCode() 相同,然而 equals() 則爲 false,因爲在散列表中,hashCode()相等即兩個鍵值對的哈希值相等,然而哈希值相等,並不一定能得出鍵值對相等。