java中hashcode()和equals()的详解

下面是关于hashcode()和equals()的官方文档解释

hashCode

     public int hashCode() 
返回该对象的哈希码值。支持此方法是为了提高哈希表(例如  java.util.Hashtable 提供的哈希表)的性能。

hashCode 的常规协定是:

  • 在 Java 应用程序执行期间,在对同一对象多次调用 hashCode 方法时,必须一致地返回相同的整数,前提是将对象进行 equals 比较时所用的信息没有被修改。从某一应用程序的一次执行到同一应用程序的另一次执行,该整数无需保持一致。
  • 如果根据 equals(Object) 方法,两个对象是相等的,那么对这两个对象中的每个对象调用 hashCode 方法都必须生成相同的整数结果。
  • 如果根据 equals(java.lang.Object) 方法,两个对象不相等,那么对这两个对象中的任一对象上调用 hashCode 方法 要求一定生成不同的整数结果。但是,程序员应该意识到,为不相等的对象生成不同整数结果可以提高哈希表的性能。

实际上,由 Object 类定义的 hashCode 方法确实会针对不同的对象返回不同的整数。(这一般是通过将该对象的内部地址转换成一个整数来实现的,但是 JavaTM 编程语言不需要这种实现技巧。)

返回:
此对象的一个哈希码值。

equals

           public boolean equals(Object obj)
指示其他某个对象是否与此对象“相等”。

equals 方法在非空对象引用上实现相等关系:

  • 自反性:对于任何非空引用值 xx.equals(x) 都应返回 true
  • 对称性:对于任何非空引用值 x 和 y,当且仅当 y.equals(x) 返回 true 时,x.equals(y) 才应返回 true
  • 传递性:对于任何非空引用值 xy 和 z,如果 x.equals(y) 返回 true,并且 y.equals(z) 返回 true,那么 x.equals(z) 应返回 true
  • 一致性:对于任何非空引用值 x 和 y,多次调用 x.equals(y) 始终返回 true 或始终返回 false,前提是对象上 equals 比较中所用的信息没有被修改。
  • 对于任何非空引用值 xx.equals(null) 都应返回 false

Object 类的 equals 方法实现对象上差别可能性最大的相等关系;即,对于任何非空引用值 x 和 y,当且仅当 x 和 y 引用同一个对象时,此方法才返回truex == y 具有值 true)。

注意:当此方法被重写时,通常有必要重写 hashCode 方法,以维护 hashCode 方法的常规协定,该协定声明相等对象必须具有相等的哈希码。

参数:
obj - 要与之比较的引用对象。
返回:
如果此对象与 obj 参数相同,则返回  true;否则返回  false

对上面的艰涩的翻译语言进行整理:

1、hashCode的存在主要是用于查找的快捷性,如Hashtable,HashMap等,hashCode是用来在散列存储结构中确定对象的存储地址的;

2、如果两个对象相同(及两个对象的地址值相同),就是适用于equals(java.lang.Object) 方法,那么这两个对象的hashCode一定要相同;

3、如果对象的equals方法被重写,那么对象的hashCode也尽量重写,并且产生hashCode使用的对象,一定要和equals方法中使用的一致,否则就会违反上面提到的第2点;

4、两个对象的hashCode相同,并不一定表示两个对象就相同,也就是不一定适用于equals(java.lang.Object) 方法,只能够说明这两个对象在散列存储结构中,如Hashtable,他们“存放在同一个桶里”

5、两个对象的 hashCode不同,则equals(java.lang.Object) 一定不同。

本段摘自互联网

1.hashcode是用来查找的,如果你学过数据结构就应该知道,在查找和排序这一章有
例如内存中有这样的位置
0  1  2  3  4  5  6  7  
而我有个类,这个类有个字段叫ID,我要把这个类存放在以上8个位置之一,如果不用hashcode而任意存放,那么当查找时就需要到这八个位置里挨个去找,或者用二分法一类的算法。
但如果用hashcode那就会使效率提高很多。
我们这个类中有个字段叫ID,那么我们就定义我们的hashcode为ID%8,然后把我们的类存放在取得得余数那个位置。比如我们的ID为9,9除8的余数为1,那么我们就把该类存在1这个位置,如果ID是13,求得的余数是5,那么我们就把该类放在5这个位置。这样,以后在查找该类时就可以通过ID除 8求余数直接找到存放的位置了。


2.但是如果两个类有相同的hashcode怎么办呢(我们假设上面的类的ID不是唯一的),例如9除以8和17除以8的余数都是1,那么这是不是合法的,回答是:可以这样。那么如何判断呢?在这个时候就需要定义 equals了。
也就是说,我们先通过 hashcode来判断两个类是否存放某个桶里,但这个桶里可能有很多类,那么我们就需要再通过 equals 来在这个桶里找到我们要的类。
那么。重写了equals(),为什么还要重写hashCode()呢?
想想,你要在一个桶里找东西,你必须先要找到这个桶啊,你不通过重写hashcode()来找到桶,光重写equals()有什么用啊

看下面的例子:

package com.java.hashcode;

public class hashcode {

	int id;

	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	@Override
	public int hashCode() {
		// 重新hashcode方法 hashcode值相同。
		return this.id;
	}

	public hashcode() {

	}

}
客户端

package com.java.hashcode;

import java.util.HashSet;

public class hashcodeTest {

	/**
	 * @param args
	 */
	public static void main(String[] args) {

		HashSet<hashcode>   ha=new HashSet<hashcode>();
		
		hashcode a = new hashcode();
		
		hashcode b = new hashcode();
		a.setId(1);
		b.setId(1);
		System.out.println(a.hashCode()==b.hashCode());//hashcode值相同
		
		System.out.println(a.equals(b));//hashcode值相同,但是两个对象不相等。我们没有重写object的equal方法,所以会调用默认的equals方法,比较两个对象的
		                                                                  //地址值,发现不是同一个对象
                ha.add(a);
                ha.add(b);
                System.out.println(ha);//默认的是getClass().getName() + '@' + Integer.toHexString(hashCode()),类名+@+hashcode值
		/**
		 * 运行结果:
		 * true
                   false
                  [com.java.hashcode.hashcode@1, com.java.hashcode.hashcode@1]
                  hashset里面包含相同的对象,显然这个不符合hashset的定义,下面我们就要重新定义equals方法。
		 */
        
	}

}
下面重新定义equals方法:

package com.java.hashcode;

public class hashcode {

	int id;
	
    String name;
    
    int[]  array;//思考一下?我们定义了,name 字段和一个整形数组  equals是时候该怎么样比较?  是比较他们的存储地址?还是比较他们的值?数组又该如何去比较?
                             //我觉得应该是比较他们的值,你觉得呢?  但是数组比较就会很麻烦,记得原来学习集合框架的时候,hashset中最好是添加固定不变的对象,像这种有不确定值
                            //的对象,比较的确好麻烦啊
	public int[] getArray() {
		return array;
	}

	public void setArray(int[] array) {
		this.array = array;
	}
	
	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}
	
	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	@Override
	public int hashCode() {
		// 重新hashcode方法 hashcode值相同。
		return this.id;
	}

	public hashcode() {

	}

	@Override
	public boolean equals(Object obj) {
		
         if(obj==null){
        	 
        	 return false;
         }
		
         if(obj==this){  
        	 
        	 return true;
         }
		if (obj instanceof hashcode) {  //obj和this是同一类对象,看属性值是否相同

			hashcode hs = (hashcode) obj;

			if (hs.id == this.id) {

				return true;
			}

		}

		return false;
	}



}
客户端:

package com.java.hashcode;

import java.util.HashSet;

public class hashcodeTest {

	/**
	 * @param args
	 */
	public static void main(String[] args) {

		HashSet<hashcode> ha = new HashSet<hashcode>();

		hashcode a = new hashcode();

		hashcode b = new hashcode();
		
		a.setId(1);	
		b.setId(1);
		System.out.println(a.hashCode() == b.hashCode());// hashcode值相同

		System.out.println(a.equals(b));// hashcode值相同,但是两个对象不相等。调用我们重写object的equal方法。
										
		ha.add(a);
		ha.add(b);
		System.out.println(ha);// 默认的是getClass().getName() + '@' +
								// Integer.toHexString(hashCode()),类名+@+hashcode值
//		运行结果:
//		true
//		true
//		[com.java.hashcode.hashcode@1]

//		调用我们覆盖的父类的equals方法,两个对象比较会认为他们是同一个对象。
		
	}

}

你可能感兴趣的:(数据结构,性能,equals,Hashtable)