java中equal方法和hashCode的理解

第一:两个都是Object的通用方法。

第二:Java语言对equals()的要求如下,这些要求是必须遵循的: 

• 对称性:如果x.equals(y)返回是“true”,那么y.equals(x)也应该返回是“true”。 
• 反射性:x.equals(x)必须返回是“true”。 
• 类推性:如果x.equals(y)返回是“true”,而且y.equals(z)返回是“true”,那么z.equals(x)也应该返回是“true”。 
• 还有一致性:如果x.equals(y)返回是“true”,只要x和y内容一直不变,不管你重复x.equals(y)多少次,返回都是“true”。 
• 任何情况下,x.equals(null),永远返回是“false”;x.equals(和x不同类型的对象)永远返回是“false”。


下面是String.java中equals的方法

/**
     * Compares this string to the specified object.  The result is {@code
     * true} if and only if the argument is not {@code null} and is a {@code
     * String} object that represents the same sequence of characters as this
     * object.
     *
     * @param  anObject
     *         The object to compare this {@code String} against
     *
     * @return  {@code true} if the given object represents a {@code String}
     *          equivalent to this string, {@code false} otherwise
     *
     * @see  #compareTo(String)
     * @see  #equalsIgnoreCase(String)
     */
    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;
    }



第三:hashCode的规则

1.在 Java 应用程序执行期间,在同一对象上多次调用 hashCode 方法时,必须一致地返回相同的整数,前提是对象上 equals 比较中所用的信息没有被修改。从某一应用程序的一次执行到同一应用程序的另一次执行,该整数无需保持一致。   
2.如果根据 equals(Object) 方法,两个对象是相等的,那么在两个对象中的每个对象上调用 hashCode 方法都必须生成相同的整数结果。   
以下情况不 是必需的:如果根据 equals(java.lang.Object) 方法,两个对象不相等,那么在两个对象中的任一对象上调用 hashCode 方法必定会生成不同的整数结果。但是,程序员应该知道,为不相等的对象生成不同整数结果可以提高哈希表的性能。   
3.实际上,由 Object 类定义的 hashCode 方法确实会针对不同的对象返回不同的整数。(这一般是通过将该对象的内部地址转换成一个整数来实现的,但是 JavaTM 编程语言不需要这种实现技巧。)   


下面是String.java中的hashCode函数

/**
     * Returns a hash code for this string. The hash code for a
     * <code>String</code> object is computed as
     * <blockquote><pre>
     * s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]
     * </pre></blockquote>
     * using <code>int</code> arithmetic, where <code>s[i]</code> is the
     * <i>i</i>th character of the string, <code>n</code> is the length of
     * the string, and <code>^</code> indicates exponentiation.
     * (The hash value of the empty string is zero.)
     *
     * @return  a hash code value for this object.
     */
    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;
    }


第四:《Effective Java》中提出了一种简单通用的hashCode算法

1. 初始化一个整形变量,为此变量赋予一个非零的常数值,比如int result = 17;
2. 选取equals方法中用于比较的所有域,然后针对每个域的属性进行计算:
  (1) 如果是boolean值,则计算f ? 1:0
  (2) 如果是byte\char\short\int,则计算(int)f
  (3) 如果是long值,则计算(int)(f ^ (f >>> 32))
  (4) 如果是float值,则计算Float.floatToIntBits(f)
  (5) 如果是double值,则计算Double.doubleToLongBits(f),然后返回的结果是long,再用规则(3)去处理long,得到int
  (6) 如果是对象应用,如果equals方法中采取递归调用的比较方式,那么hashCode中同样采取递归调用hashCode的方式。否则需要为这个域计算一个范式,比如当这个域的值为null的时候,那么hashCode 值为0
  (7) 如果是数组,那么需要为每个元素当做单独的域来处理。如果你使用的是1.5及以上版本的JDK,那么没必要自己去重新遍历一遍数组,java.util.Arrays.hashCode方法包含了8种基本类型数组和引用数组的hashCode计算,算法同上,


============================测试程序============================

import java.util.HashSet;


public class NMMain {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		HashSet<NMObject> nmHS = new HashSet<NMMain.NMObject>();
		NMObject nmObject1 = new NMObject();
		nmObject1.m = 10;
		nmObject1.n = 8;
		
		NMObject nmObject2 = new NMObject();
		nmObject2.m = 10;
		nmObject2.n = 8;
		
		NMObject nmObject3 = new NMObject();
		nmObject3.m = 8;
		nmObject3.n = 10;
		
		nmHS.add(nmObject1);
		nmHS.add(nmObject2);
		nmHS.add(nmObject3);
		
	}

	
	public static class NMObject{
		public int n;
		public int m;
		
		@Override
		public boolean equals(Object obj) {
			// TODO Auto-generated method stub
			if(!(obj instanceof NMObject)){
				return false;
			}
			return n == ((NMObject)obj).n && m == ((NMObject)obj).m;
		}
		
		@Override
		public int hashCode() {
			// TODO Auto-generated method stub
			return n+m;
		}
	}
}


nmHS中有两个对象,因为NMObject中覆盖了equals和hashCode的方法,nmObject1和nmObject2中n,m值相等所以两者被认为是同一个对象。而nmObject3虽然hash值相同但是他们equals方法不相等,所以认为是不同的对象。

判断相等的规则:

条件一:判断hashCode是否相等,如果不相等就证明了两个对象不相等;如果相等进入“条件二”

条件二:判断equals是否相等,如果不相等就证明两个对象不相等;如果相等就证明是真的不相等啦


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值