equal hashCode == 之间关系

1、首先来回答一个问题,hashCode equal  ==  三者包含意义是什么?

==,当被==对象为简单类型时,比较的是值是否相同;如果被==者为对象时,== 比较的是被==对象的是否为同一对象引用,既对象物理地址是否相同。

equal :

源码如下:

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

 显然在Object 对象中equal 方法是直接比较对象的物理地址是否相同。

 

再说hashCode是神马?

 

 /**
     *As much as is reasonably practical, the hashCode method defined by
     * class {@code Object} does return distinct integers for distinct
     * objects. (This is typically implemented by converting the internal
     * address of the object into an integer)
  */

public native int hashCode();

 由此可见hashCode 实质为对象存储地址。

 

 

2、qual 和 hashCode 关系如何?

 

在hashCode 方法注解中有这么一段话,如下:

If two objects are equal according to the {@code equals(Object)}method, then calling the {@code hashCode} method on each of the two objects must produce the same integer result。

如果两个对象equal , 那么两个对象产生的hashCode必须相同

 

还有如下一段话,

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 {@code hashCode} 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 hash tables.

翻译过来就是如果两对象的hashCode 相同,两对象并不一定equal

 

3、怎样重写eqaul 和 hashCode?

 

eqaul 方法重写必须满足以下条件,还是来看源码注解吧:

 /**
     * 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>
     ***/
 
  • 自反性(reflexive)。对于任意不为null的引用值x,x.equals(x)一定是true

  • 对称性(symmetric)。对于任意不为null的引用值xy,当且仅当x.equals(y)true时,y.equals(x)也是true

  • 传递性(transitive)。对于任意不为null的引用值xyz,如果x.equals(y)true,同时y.equals(z)true,那么x.equals(z)一定是true

  • 一致性(consistent)。对于任意不为null的引用值xy,如果用于equals比较的对象信息没有被修改的话,多次调用时x.equals(y)要么一致地返回true要么一致地返回false

  • 对于任意不为null的引用值xx.equals(null)返回false

 

hashCode 

 /**
     * Returns a hash code value for the object. This method is
     * supported for the benefit of hash tables such as those provided by
     * {@link java.util.HashMap}.
     * <p>
     * The general contract of {@code hashCode} is:
     * <ul>
     * <li>Whenever it is invoked on the same object more than once during
     *     an execution of a Java application, the {@code hashCode} method
     *     must consistently return the same integer, provided no information
     *     used in {@code equals} 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 {@code equals(Object)}
     *     method, then calling the {@code hashCode} 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 {@code hashCode} 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 hash tables.
     * </ul>
     * <p>
   ***/
  • 在一个Java应用的执行期间,如果一个对象提供给equals做比较的信息没有被修改的话,该对象多次调用hashCode()方法,该方法必须始终如一返回同一个integer。当然如果同一应用的不同执行,其返回的hashcode 不需要一致

  • 如果两个对象根据equals(Object)方法是相等,那么调用二者各自的hashCode()方法必须产生同一个integer结果。

  • 如果两对象不相等,调用二者各自的hashCode()方法生成integer结果没有说一定要求不相同。然而,程序员应该意识到对于不同的对象产生不同的integer结果,有可能会提高hash table的性能。

上述为java api 对hashCode() 和equal() 方法的规定,具体重写呢,一般根据实际需求来,但equal 大多重写跟据内容相同来做比较。hashCode 怎样重写呢?

下面来看一下String 的重写

    public int hashCode() {
        int h = hash;
        if (h == 0 && value.length > 0) {
            char val[] = value;

            for (int i = 0; i < value.length; i++) {
                h = 31 * h + val[i];
            }
            hash = h;
        }
        return h;
    }
 这里为什么会用31 这个数字,在   Effective Java是这么解释的

 

According to Joshua Bloch's Effective Java (a book that can't be recommended enough, and which I bought thanks to continual mentions on stackoverflow):
The value 31 was chosen because it is an odd prime. If it were even and the multiplication overflowed, information would be lost, as multiplication by 2 is equivalent to shifting. The advantage of using a prime is less clear, but it is traditional. A nice property of 31 is that the multiplication can be replaced by a shift and a subtraction for better performance: 31 * i == (i << 5) - i. Modern VMs do this sort of optimization automatically.
(from Chapter 3, Item 9: Always override hashcode when you override equals, page 48)
        根据 Joshua Bloch 的著作『Effective Java』(一本无论如何推荐都不为过的书,它是一本我根据 StackOverflow 上的不断推荐购买的书)

设计者选择 31 这个值是因为它是一个奇质数。如果它是一个偶数,在使用乘法当中产生数值溢出时,原有数字的信息将会丢失,因为乘以二相当于位移。

选择质数的优势不是那么清晰,但是这是一个传统。31 的一个优良的性质是:乘法可以被位移和减法替代


31 * i == (i << 5) - i

现代的 VM 可以自行完成这个优化。


来自书的第三章,条目 9 : 永远在你复写 equals 方法的时候永远复写 hashCode 方法

猜你喜欢

转载自qiuxia812913.iteye.com/blog/2305846
今日推荐