码迷,mamicode.com
首页 > 其他好文 > 详细

Object对象详解(三)之hashCode与equals

时间:2015-07-30 23:27:08      阅读:206      评论:0      收藏:0      [点我收藏+]

标签:java

从学习Java开始,就从各个师兄、各种书籍、各大网站听到、看到,重写equals方法必须重写hashCode方法。重写equals方法必须重写hashCode方法。重写equals方法必须重写hashCode方法。

那么为什么呢?今天就详细剖析一下equals和hashCode!
equals方法是比较两个对象实例是否相等。Object中equals方法的描述为:

    public boolean equals(Object obj) {
        return (this == obj);
    }

也就是默认情况下,equals是比较两个对象的引用是否相等,这个情况下除非两个对象引用指向同一个对象,否则都会返回false。而实际场景中,我们并不需要比较两个对象的地址,而是比较它们的内同通过是否相等,这就需要我们重写equals方法。
那么是不是就简单的比较下内容是否相等呢?有什么需要注意的吗?
看下Java源码的描述:

思考这样的问题:
1. 假设两个对象的内容一样,那么它们调用equals方法会相等吗?
2. 如果在状态不改变的情况下,两次比较的结果不一样,你会不会抓狂?
3. 什么情况下返回true,什么情况下又返回false?
让我们一个一个的看,如果两个对象内容相同,但类型不一样,它们还equals吗?

/**
     * Indicates whether some other object is "equal to" this one.
     * <p>
     * The {@code equals} 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 x.equals(x)} should return
     *     {@code true}.
     * <li>It is <i>symmetric</i>: for any non-null reference values
     *     {@code x} and {@code y}, {@code x.equals(y)}
     *     should return {@code true} if and only if
     *     {@code y.equals(x)} returns {@code true}.
     * <li>It is <i>transitive</i>: for any non-null reference values
     *     {@code x}, {@code y}, and {@code z}, if
     *     {@code x.equals(y)} returns {@code true} and
     *     {@code y.equals(z)} returns {@code true}, then
     *     {@code x.equals(z)} should return {@code true}.
     * <li>It is <i>consistent</i>: for any non-null reference values
     *     {@code x} and {@code y}, multiple invocations of
     *     {@code x.equals(y)} consistently return {@code true}
     *     or consistently return {@code false}, provided no
     *     information used in {@code equals} comparisons on the
     *     objects is modified.
     * <li>For any non-null reference value {@code x},
     *     {@code x.equals(null)} should return {@code false}.
     * </ul>
     * <p>
     */
    public boolean equals(Object obj) {
        return (this == obj);
    }

SUN已经说了,equals需要遵守的规则(一下x,y均不为null):
1. 自反性(x.equals(x) 为true)
2. 一致性(x.equals(y)或y.equals(x)在没有x,y指向的对象没有改变的情况下,多次比较的结果应该是一致且明确的)
3. 传递性(x.equals(y) && y.equals(z)为true ,则x.equals(z)为true)
4. 对称性(x.equals(y) == y.equals(x) 始终为true)
下面上例子(String重写了equals):

public boolean equals(Object anObject) {
        if (this == anObject) {
            return true;
        }
        if (anObject instanceof String) {
            String anotherString = (String) anObject;
            int n = value.length;
            if (n == anotherString.value.length) {
                char v1[] = value;
                char v2[] = anotherString.value;
                int i = 0;
                while (n-- != 0) {
                    if (v1[i] != v2[i])
                            return false;
                    i++;
                }
                return true;
            }
        }
        return false;
    }

那么为什么说重写equals,就必须重写hashCode呢?
源码中对hashCode方法的返回值的描述:a hash code value for this object.This method is supported for the benefit of hash tables such as those provided by java.util.HashMap.
这里提到了HashMap,再看HashMap中使用hashCode的地方

 final int hash(Object k) {
        int h = 0;
        if (useAltHashing) {
            if (k instanceof String) {
                return sun.misc.Hashing.stringHash32((String) k);
            }
            h = hashSeed;
        }

        h ^= k.hashCode();

        // This function ensures that hashCodes that differ only by
        // constant multiples at each bit position have a bounded
        // number of collisions (approximately 8 at default load factor).
        h ^= (h >>> 20) ^ (h >>> 12);
        return h ^ (h >>> 7) ^ (h >>> 4);
    }

public V put(K key, V value) {
        if (key == null)
            return putForNullKey(value);
        int hash = hash(key);
        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;
    }

从上面看到,HashMap是基于HashTable来存放元素的,在存放K-V时,会将K的hashCode作为hash函数的变量来计算K的位置,如果两个对象equals为真,但hashCode不等,那么它们将被散列到map的不同位置,最后结果就是map中存在两个K equals的对象,这就违反了Map要求Key唯一的约定。
因此,
如果重写equals,请重写hashCode。
如果重写equals,请重写hashCode。
如果重写equals,请重写hashCode。

版权声明:本文为博主原创文章,未经博主允许不得转载。

Object对象详解(三)之hashCode与equals

标签:java

原文地址:http://blog.csdn.net/u013769320/article/details/47156767

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!