package com.wangzhu.map; import java.util.HashMap; /** * hashCode方法的主要作用是為了配合基於雜湊的集合一起正常執行,<br/> * 這樣的雜湊集合包括HashSet、HashMap以及HashTable。<br/> * 能否可以直接根據hashCode值判斷兩個物件是否相等呢?<br/> * 答案:肯定是不可以的,因為不同的物件可能會生成相同的hashCode值。<br/> * 雖然不能根據hashCode值判斷兩個物件是否相等,但是可以直接根據hashCode值判斷兩個物件不等,<br/> * 如果兩個物件的hashCode值不等,則必定是兩個不同的物件。如果要判斷兩個物件是否真正相等,則必須通過equals方法。<br/> * 也就是說對於兩個物件,如果呼叫equals方法得到的結果為true,則兩個物件的hashCode值必定相等。<br/> * 如果equals方法得到的結果為,則兩個物件的hashCode值不一定不同; <br/> * 如果兩個物件的hashCode值不等,則equals方法得到的結果必為;<br/> * 如果兩個物件的hashCode值相等,則equals方法得到的結果未知。<br/> * * @author wangzhu * @date 2015-2-1下午11:22:42 * */ public class DemoMap2 { /** * @param args */ public static void main(String[] args) { Student stu = new Student(21, "John"); HashMap<Student, Integer> map = new HashMap<Student, Integer>(); map.put(stu, 1); System.out.println(map.get(stu));// 1 System.out.println(map.get(new Student(21, "John")));// 1 /** * 若Student只重寫equals方法而沒有沒有重寫hashCode方法時,則輸出為null */ stu.setAge(22); System.out.println(map.get(stu));// null /** * 在程式執行期間,只要equals方法的比較操作用到的資訊沒有被修改,<br/> * 那麼對這同一個物件呼叫多次, hashCode方法必須始終如一地返回同一個整數。<br/> * * 設計hashCode()時最終稿的因素就是:無論何時,對同一個物件呼叫hashCode()都應該產生同樣的值。<br/> * 如果在將一個物件用put()新增進HashMap時產生一個hashCode值,而用get()取出時卻產生另一個hashCode值,<br/> * 那麼就無法獲取該物件了。所以如果你的hashCode方法依賴於物件中易變的資料,使用者就要當心了,<br/> * 因為此資料變化時,hashCode() 方法就會生成一個不同的雜湊碼。<br/> */ } } class Student { int age; String name; public Student(int age, String name) { super(); this.age = age; this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public int hashCode() { final int prime = 31; int result = 1; result = (prime * result) + age; result = (prime * result) + ((name == null) ? 0 : name.hashCode()); return result; } /** * 重寫時,需要讓equals方法與hashCode方法始終在邏輯上保持一致性。 */ @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (this.getClass() != obj.getClass()) { return false; } Student other = (Student) obj; if (age != other.age) { return false; } if (name == null) { if (other.name != null) { return false; } } else if (!name.equals(other.name)) { return false; } return true; } }
下面是HashMap中的put方法【JDK1.6】
public V put(K key, V value) { if (key == null) return putForNullKey(value); int hash = hash(key.hashCode()); int i = indexFor(hash, table.length); for (Entry<K,V> e = table[i]; e != null; e = e.next) { Object k; if (e.hash == hash && ((k = e.key) == key || key.equals(k))) { V oldValue = e.value; e.value = value; e.recordAccess(this); return oldValue; } } modCount++; addEntry(hash, key, value, i); return null; }
備註:put方法是用來向HashMap中新增新的元素。從put方法的具體實現可知,其會先呼叫hashCode方法得到該元素的hashCode值【經過處理的】,然後檢視其是否存在於table陣列中,如果存在則呼叫equals方法來確定是否是存在該元素;如果存在,則更新value值,否則將新的元素新增到HashMap中。
下面是HashMap中的get方法【JDK1.6】
public V get(Object key) { if (key == null) return getForNullKey(); int hash = hash(key.hashCode()); for (Entry<K,V> e = table[indexFor(hash, table.length)]; e != null; e = e.next) { Object k; if (e.hash == hash && ((k = e.key) == key || key.equals(k))) return e.value; } return null; }
備註:get方法是用來將HashMap中對應Key的值Value取出來。從get方法的具體實現可知,其會先呼叫hashCode方法得到該元素的hashCode值,然後檢視其在table陣列中是否存在,如果存在則呼叫equals方法來確定是Key對應的元素,並返回其Value,否則返回null。