首先我们知道hashmap的key是可以直接使用String来充当的,而如果我们想用对象来作为key,那么我们必须重写这个对象的hashCode方法以及equals方法。
看看下面的地址:
public class HashMapTest {
private static class Key{
int key_hash;
int key_value;
public Key(int hash,int value){
this.key_hash=hash;
this.key_value=value;
}
@Override
public boolean equals(Object o) {
Key k=(Key)o;
return this.key_value==k.key_value;
}
}
public static void main(String[] args){
HashMap<Key,String> map= new HashMap<Key,String>();
Key key=new Key(1,1);
map.put(key,"hello");
System.out.print(map.get(new Key(1,1)));
}
}
它的运行结果是null,也就是没有这个值。
因此我们来看看hashmap中,是怎么通过hash计算来把元素定位的。
final int hash(Object k) {
int h = hashSeed;
if (0 != h && k instanceof String) {
return sun.misc.Hashing.stringHash32((String) k);
}
h ^= k.hashCode();//直接调用hashCode方法计算位置
h ^= (h >>> 20) ^ (h >>> 12);
return h ^ (h >>> 7) ^ (h >>> 4);
}
可见当不是传入String类型而是传入其他类型时,它是直接调用它的hashCode,所以上例中,我们并没有重写hashCode方法,
而当没有重写时,hashCode是通过对象计算的,因此不同的对象hashCode值也不同。
那上个例子中我们不重写eaquls只重写hashCode方法行不行呢? 答案是否定的。
我们看看hashMap中的get方法是怎么实现的。
final Entry<K,V> getEntry(Object key) {
if (size == 0) {
return null;
}
//通过key的hashcode值计算hash值
int hash = (key == null) ? 0 : hash(key);
//indexFor (hash&length-1) 获取最终数组索引,然后遍历链表,通过equals方法比对找出对应记录
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 != null && key.equals(k))))
return e;
}
return null;
}
可以看到:
((k = e.key) == key || (key != null && key.equals(k))))
在get元素时,计算完了hash值之后还要进行key是否相等的比较,如果我们没有重写equals方法,那么默认比较的是对象的地址,所以也是不行的。
所以最终改成:
public class HashMapTest {
private static class Key{
int key_hash;
int key_value;
public Key(int hash,int value){
this.key_hash=hash;
this.key_value=value;
}
@Override
public int hashCode(){
return key_value;
}
@Override
public boolean equals(Object o){
Key k=(Key)o;
return key_value==k.key_value;
}
}
public static void main(String[] args){
HashMap<Key,String> map= new HashMap<Key,String>();
Key key=new Key(1,1);
map.put(key,"hello");
System.out.print(map.get(new Key(1,1)));
}
}
就可以得到结果:hello 了。