源码剖析HashMap--当key为Object时为什么要重写hashcode与equals方法

首先我们知道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 map= new HashMap();
		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 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 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 map= new HashMap();
		Key key=new Key(1,1);
		map.put(key,"hello");
		System.out.print(map.get(new Key(1,1)));
		
	}
	
}

就可以得到结果:hello 了。









你可能感兴趣的:(java)