关于Java覆盖equals方法时必须覆盖hashCode方法

来源:互联网 发布:数据库服务器配置 编辑:程序博客网 时间:2024/05/04 17:37

Java中的对象自动继承Object类,而Object类实现了equals方法和hashCode方法:

    /**     * Returns a hash code value for the object. This method is      * supported for the benefit of hashtables such as those provided by      * <code>java.util.Hashtable</code>.      * <p>     * The general contract of <code>hashCode</code> is:      * <ul>     * <li>Whenever it is invoked on the same object more than once during      *     an execution of a Java application, the <tt>hashCode</tt> method      *     must consistently return the same integer, provided no information      *     used in <tt>equals</tt> comparisons on the object is modified.     *     This integer need not remain consistent from one execution of an     *     application to another execution of the same application.      * <li>If two objects are equal according to the <tt>equals(Object)</tt>     *     method, then calling the <code>hashCode</code> method on each of      *     the two objects must produce the same integer result.      * <li>It is <em>not</em> required that if two objects are unequal      *     according to the {@link java.lang.Object#equals(java.lang.Object)}      *     method, then calling the <tt>hashCode</tt> method on each of the      *     two objects must produce distinct integer results.  However, the      *     programmer should be aware that producing distinct integer results      *     for unequal objects may improve the performance of hashtables.     * </ul>     * <p>     * As much as is reasonably practical, the hashCode method defined by      * class <tt>Object</tt> does return distinct integers for distinct      * objects. (This is typically implemented by converting the internal      * address of the object into an integer, but this implementation      * technique is not required by the      * Java<font size="-2"><sup>TM</sup></font> programming language.)     *     * @return  a hash code value for this object.     * @see     java.lang.Object#equals(java.lang.Object)     * @see     java.util.Hashtable     */    public native int hashCode();    /**     * Indicates whether some other object is "equal to" this one.     * <p>     * The <code>equals</code> method implements an equivalence relation     * on non-null object references:     * <ul>     * <li>It is <i>reflexive</i>: for any non-null reference value     *     <code>x</code>, <code>x.equals(x)</code> should return     *     <code>true</code>.     * <li>It is <i>symmetric</i>: for any non-null reference values     *     <code>x</code> and <code>y</code>, <code>x.equals(y)</code>     *     should return <code>true</code> if and only if     *     <code>y.equals(x)</code> returns <code>true</code>.     * <li>It is <i>transitive</i>: for any non-null reference values     *     <code>x</code>, <code>y</code>, and <code>z</code>, if     *     <code>x.equals(y)</code> returns <code>true</code> and     *     <code>y.equals(z)</code> returns <code>true</code>, then     *     <code>x.equals(z)</code> should return <code>true</code>.     * <li>It is <i>consistent</i>: for any non-null reference values     *     <code>x</code> and <code>y</code>, multiple invocations of     *     <tt>x.equals(y)</tt> consistently return <code>true</code>     *     or consistently return <code>false</code>, provided no     *     information used in <code>equals</code> comparisons on the     *     objects is modified.     * <li>For any non-null reference value <code>x</code>,     *     <code>x.equals(null)</code> should return <code>false</code>.     * </ul>     * <p>     * The <tt>equals</tt> method for class <code>Object</code> implements      * the most discriminating possible equivalence relation on objects;      * that is, for any non-null reference values <code>x</code> and     * <code>y</code>, this method returns <code>true</code> if and only     * if <code>x</code> and <code>y</code> refer to the same object     * (<code>x == y</code> has the value <code>true</code>).     * <p>     * Note that it is generally necessary to override the <tt>hashCode</tt>     * method whenever this method is overridden, so as to maintain the     * general contract for the <tt>hashCode</tt> method, which states     * that equal objects must have equal hash codes.      *     * @param   obj   the reference object with which to compare.     * @return  <code>true</code> if this object is the same as the obj     *          argument; <code>false</code> otherwise.     * @see     #hashCode()     * @see     java.util.Hashtable     */    public boolean equals(Object obj) {return (this == obj);    }

Object类中的hashCode()已自动实现为不同的对象生成不同的hashCode,所以,当我们创建一个新的类时,即使以这个类为基准创建了两个完全相同的对象(对象中的元素完全相同),这两个相同对象的hashCode也是不同的:

import java.util.Map;import java.util.Map.Entry;import com.google.common.base.Objects;import com.google.common.collect.Maps;public class Name {    String id;    Name(String id) {        this.id = id;    }    @Override    public boolean equals(Object obj) {        Name otherName = (Name) obj;        return Objects.equal(this.id, otherName.id);    }    @Override    public String toString() {        return this.getClass().getSimpleName() + "@" + this.id + "&" + this.hashCode();    }    public static void main(String[] args) {        Name n1 = new Name("zhao");        Name n2 = new Name("zhao");        System.err.println("n1.equals(n2) = " + n1.equals(n2));        Map<Name, Integer> map = Maps.newHashMap();        map.put(n1, 1);        map.put(n2, 2);        for (Entry<Name, Integer> entry : map.entrySet()) {            System.out.println(entry.getKey() + ":" + entry.getValue());        }        System.err.println(map.get(new Name("zhao")));    }}

而Java中的Hash容器会根据Key的hashCode,将不同hashCode对象(即hashCode()不同的对象而非equals()不同的对象)散列到不同的位置,这时候在Hash容器中应用这些对象时会出现错误。所以,在覆盖equals()方法时必须覆盖hashCode()方法。如下是HashMap源码实现:

    /**     * Associates the specified value with the specified key in this map.     * If the map previously contained a mapping for the key, the old     * value is replaced.     *     * @param key key with which the specified value is to be associated     * @param value value to be associated with the specified key     * @return the previous value associated with <tt>key</tt>, or     *         <tt>null</tt> if there was no mapping for <tt>key</tt>.     *         (A <tt>null</tt> return can also indicate that the map     *         previously associated <tt>null</tt> with <tt>key</tt>.)     */    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;    }

参考文章:

1、JDK源码

2、http://www.cnblogs.com/wangliyue/p/4450747.html

3、http://www.cnblogs.com/happyPawpaw/p/3744971.html


0 0
原创粉丝点击