945   Java

1,hasCode,一般用于快捷查询对象的,比如散列存储的HashSet;每个对象会返回不同的整数,不过可能会出现相同值,虽然概率很少。为避免这种想象,所以需要equals啦

2,equals,判断对象是否相等,包括hasCode;通过equals得出两个对象相等,那么hasCode必定相等;如果equals不相等,hasCode有可能不同,也可能相同

 

具体说明:

HashSet在添加子对象时,会首先调用hasCode,判断是否存在该对象,如果hasCode不同,则表示不同的对象;如果hasCode相同,再去调用equals判断是否存在改对象;

由此可知,hashCode方法是为了减少equals方法的调用次数,从而提高程序效率,即快捷查询对象。


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 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;
    }

HashSet的get对象方法也采用类似的机制,会先调用hasCode再调用equals


public V get(Object key) {
        if (key == null)
            return getForNullKey();
        int hash = hash(key.hashCode());
        for (Entry 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;
    }

注意事项:
在重写equals时,也要重写hasCode
我们在重写equals时,觉得已经相同了,但是hasCode函数还是不同的。
HashSet在add对象时先根据hasCode判断对象,hasCode不同,所以对象不同,HaspMap会保存两个对象,即使equals相同


import java.util.HashSet;
import java.util.Set;

public class HashTest {
	private int i;

	public int getI() {
		return i;
	}

	public void setI(int i) {
		this.i = i;
	}

	public boolean equals(Object object) {
		if (object == null) {
			return false;
		}
		if (object == this) {
			return true;
		}
		if (!(object instanceof HashTest)) {
			return false;
		}
		HashTest other = (HashTest) object;
		if (other.getI() == this.getI()) {
			return true;
		}
		return false;
	}

	public final static void main(String[] args) {
		HashTest a = new HashTest();
		HashTest b = new HashTest();
		a.setI(1);
		b.setI(1);
		Set set = new HashSet();
		set.add(a);
		set.add(b);
		System.out.println("a.hasCode="+a.hashCode());
		System.out.println("b.hasCode="+ b.hashCode());
		System.out.println("a.equals(b)="+a.equals(b));
		System.out.println("set:"+set);
	}
}
a.hasCode=1794515827
b.hasCode=1167165921
a.equals(b)=true
set:[com.chinaunicom.rp.rpTemplate.web.action.HashTest@6af62373, com.chinaunicom.rp.rpTemplate.web.action.HashTest@459189e1]

正确做法时,重写equals同时重写hasCode



package com.chinaunicom.rp.rpTemplate.web.action;

import java.util.HashSet;
import java.util.Set;

public class HashTest {
	private int i;

	public int getI() {
		return i;
	}

	public void setI(int i) {
		this.i = i;
	}

	public boolean equals(Object object) {
		if (object == null) {
			return false;
		}
		if (object == this) {
			return true;
		}
		if (!(object instanceof HashTest)) {
			return false;
		}
		HashTest other = (HashTest) object;
		if (other.getI() == this.getI()) {
			return true;
		}
		return false;
	}

	public int hashCode() {
		return i % 10;
	}

	public final static void main(String[] args) {
		HashTest a = new HashTest();
		HashTest b = new HashTest();
		a.setI(1);
		b.setI(1);
		Set set = new HashSet();
		set.add(a);
		set.add(b);
		System.out.println("a.hasCode="+a.hashCode());
		System.out.println("b.hasCode="+ b.hashCode());
		System.out.println("a.equals(b)="+a.equals(b));
		System.out.println("set:"+set);
	}
}


a.hasCode=1
b.hasCode=1
a.equals(b)=true
set:[com.chinaunicom.rp.rpTemplate.web.action.HashTest@1]




Trackbacks/Pingbacks

  1.  Java equals和hasCode导致内存泄露 | LuckyBird

Leave a Reply

Your email address will not be published. Required fields are marked *