使用java的人都知道,如果覆蓋了Object的equals方法,那么必須要覆蓋hashCode方法,并且如果兩個(gè)對(duì)象用equals方法比較返回true,那么這兩個(gè)對(duì)象hashCode返回的值也必須是相等的,并且對(duì)于同一個(gè)對(duì)象,equals方法需要比較的屬性值沒有被修改,那么每次調(diào)用hashCode返回的值應(yīng)該是一致的。
那么為什么需要這樣呢,是不是所有的對(duì)象在覆蓋Object的equal方法時(shí)都需要覆蓋hashCode方法呢?下面以一個(gè)實(shí)例來說明該問題:
public class HashTest


{
@Test
public void testEqualAndHash()

{
Map<HashObject, String> map = new HashMap<HashObject, String>();
for(int i = 0; i < 10; i++)

{
HashObject o = new HashObject();
o.setId(i);
o.setIdCard("id_" + i);
o.setName("name_" + i);
o.setAddress("address_" + i);
map.put(o, o.getName());
System.out.println();
}
HashObject o = new HashObject();
o.setId(0);
o.setIdCard("id_" + 0);
o.setName("name_" + "zhangsan");
String v = map.put(o, o.getName());

/**//* 未實(shí)現(xiàn)hashcode方法,調(diào)用map的put方法將不會(huì)返回舊值,而是返回null */
System.out.println("v:" + v);
System.out.println("size:" + map.size());
}
}

public class HashObject


{
private Integer id;
private String name;
private String idCard;
private String address;
public Integer getId()

{
return id;
}
public void setId(Integer id)

{
this.id = id;
}
public String getName()

{
return name;
}
public void setName(String name)

{
this.name = name;
}
public String getIdCard()

{
return idCard;
}
public void setIdCard(String idCard)

{
this.idCard = idCard;
}
public String getAddress()

{
return address;
}
Object o = null;
public void setAddress(String address)

{
this.address = address;
}
public boolean equals(Object o)

{
if(this == o)
return true;
HashObject x = (HashObject) o;
if(x.getIdCard().equals(this.idCard))
return true;
return false;
}
// public int hashCode()
// {
//
// return 17 * 37 + this.idCard.hashCode();
//
// }
}關(guān)閉與開啟HashObject的hashCode方法的執(zhí)行結(jié)果
v:null
size:11
----------------------
v:name_0
size:10
那么為什么會(huì)這樣呢,讓我們看看
1
public V put(K key, V value)
{
2
if (key == null)
3
return putForNullKey(value);
4
/**//*對(duì)key的hashcode做hash運(yùn)算*/
5
int hash = hash(key.hashCode());
6
/**//*獲得key對(duì)應(yīng)的Entry的索引位置*/
7
int i = indexFor(hash, table.length);
8
for (Entry<K,V> e = table[i]; e != null; e = e.next)
{
9
Object k;
10
/**//*HashMap采用鏈表來解決hashcode沖突,從這里可以看出,只有hashcode相等,且equals或者地址相等,HashMap才認(rèn)為對(duì)象是相同的*/
11
if (e.hash == hash && ((k = e.key) == key || key.equals(k)))
{
12
V oldValue = e.value;
13
e.value = value;
14
e.recordAccess(this);
15
return oldValue;
16
}
17
}
18
19
modCount++;
20
addEntry(hash, key, value, i);
21
return null;
22
} HashMap的實(shí)現(xiàn)就一目了然了。HashMap采用Entry數(shù)組作為存儲(chǔ)<key,value>的數(shù)據(jù)結(jié)構(gòu),數(shù)組的索引是同過對(duì)key的hashcode做hash運(yùn)算獲得的,HashMap采用鏈表來解決hash沖突問題。下面讓我們看看HashMap的put方法實(shí)現(xiàn):
posted on 2012-08-16 18:39
zhangxl 閱讀(425)
評(píng)論(0) 編輯 收藏