== : 它的作用是判斷兩個對象的地址是不是相等。即判斷兩個對象是不是同一個對象(基本數據類型比較的是值,引用數據類型比較的是內存地址)。
equals() : 它的作用也是判斷兩個對象是否相等。但它一般有兩種使用情況:
- 情況1:類沒有覆蓋 equals() 方法。則通過 equals() 比較該類的兩個對象時,等價於通過“==”比較這兩個對象。
//Object的equals方法實現
public boolean equals(Object obj) {
return (this == obj);
}
- 情況2:類覆蓋了 equals() 方法。一般,我們都覆蓋 equals() 方法來比較兩個對象的內容是否相等;若它們的內容相等,則返回 true (即,認爲這兩個對象相等)。
//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;
}
示例
public class test1 {
public static void main(String[] args) {
String a = new String("ab"); // a 爲一個引用
String b = new String("ab"); // b爲另一個引用,對象的內容一樣
String aa = "ab"; // 放在常量池中
String bb = "ab"; // 從常量池中查找
if (aa == bb) // true
System.out.println("aa==bb");
if (a == b) // false,非同一對象
System.out.println("a==b");
if (a.equals(b)) // true
System.out.println("aEQb");
if (42 == 42.0) { // true
System.out.println("true");
}
}
}
hashCode() 的作用是獲取哈希碼,也稱爲散列碼;它實際上是返回一個int整數。這個哈希碼的作用是確定該對象在哈希表中的索引位置。兩個對象相同,hash一定相同,反之不一定。
//String類的hashcode實現
public int hashCode() {
int h = hash;
if (h == 0 && value.length > 0) { //還沒有計算hash
char val[] = value;
for (int i = 0; i < value.length; i++) {
h = 31 * h + val[i];
}
hash = h;
}
return h;
}
當類作爲哈希表的key時,一定要同時重寫equals()和hashcode()。
哈希表添加一個鍵值對的邏輯:
- 調用key的hashcode()獲得哈希碼,此哈希碼就是元素的存放位置;
- 如果哈希表對應的位置爲空,則直接插入新元素即可,否則轉到步驟3
- 由於hashcode相等並不表明對象一定相等,故再調用equals()方法判斷對象是否相同,如果不同則進行哈希衝突(找到空位存入元素),如果相同則該key賦新值。
/**
* Implements Map.put and related methods.
*
* @param hash hash for key
* @param key the key
* @param value the value to put
* @param onlyIfAbsent if true, don't change existing value
* @param evict if false, the table is in creation mode.
* @return previous value, or null if none
*/
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
boolean evict) {
Node<K,V>[] tab; Node<K,V> p; int n, i;
if ((tab = table) == null || (n = tab.length) == 0) //初始化哈希表
n = (tab = resize()).length;
if ((p = tab[i = (n - 1) & hash]) == null) //步驟1
tab[i] = newNode(hash, key, value, null);
else {
Node<K,V> e; K k;
if (p.hash == hash &&
((k = p.key) == key || (key != null && key.equals(k)))) //步驟3
e = p;
else if (p instanceof TreeNode)
e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
else {
for (int binCount = 0; ; ++binCount) { //解決哈希衝突
if ((e = p.next) == null) {
p.next = newNode(hash, key, value, null);
if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
treeifyBin(tab, hash);
break;
}
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))
break;
p = e;
}
}
if (e != null) { // existing mapping for key
V oldValue = e.value;
if (!onlyIfAbsent || oldValue == null)
e.value = value;
afterNodeAccess(e);
return oldValue;
}
}
++modCount;
if (++size > threshold)
resize();
afterNodeInsertion(evict);
return null;
}