HashCode的做用(以java为例)

关于Hashcode的做用 
  总的来讲,Java中的集合(Collection)有两类,一类是List,再有一类是Set。前者集合内的元素是有序的,元素能够重复;后者元素无序,但元素不可重复。 
       要想保证元素不重复,可两个元素是否重复应该依据什么来判断呢?这就是Object.equals方法了。可是,若是每增长一个元素就检查一 次,那么当元素不少时,后添加到集合中的元素比较的次数就很是多了。也就是说,若是集合中如今已经有1000个元素,那么第1001个元素加入集合时,它 就要调用1000次equals方法。这显然会大大下降效率。 
       因而,Java采用了哈希表的原理。哈希算法也称为散列算法,是将数据依特定算法直接指定到一个地址上。这样一来,当集合要添加新的元素时,先调用这个元素的hashCode方法,就一会儿能定位到它应该放置的物理位置上。若是这个位置上没有元素,它就能够 直接存储在这个位置上,不用再进行任何比较了;若是这个位置上已经有元素了,就调用它的equals方法与新元素进行比较,相同的话就不存了;不相同,也就是发生了Hash key相同致使冲突的状况,那么就在这个Hash key的地方产生一个链表,将全部产生相同hashcode的对象放到这个单链表上去,串在一块儿。因此这里存在一个冲突解决的问题(不多出现)。这样一来实际调用equals方法的次数就大大下降了,几乎只须要一两次。 
       因此,Java对于eqauls方法和hashCode方法是这样规定的: 
           一、若是两个对象相等,那么它们的hashCode值必定要相等; 
           二、若是两个对象的hashCode相等,它们并不必定相等。 
上面说的对象相等指的是用eqauls方法比较。 

============================================================ 
如何理解hashCode的做用: 
============================================================ 
以java.lang.Object来理解,JVM每new一个Object,它都会将这个Object丢到一个Hash哈希表中去,这样的话,下次作Object的比较或者取这个对象的时候,它会根据对象的hashcode再从Hash表中取这个对象。这样作的目的是提升取对象的效率。具体过程是这样: 
1.new Object(),JVM根据这个对象的Hashcode值,放入到对应的Hash表对应的Key上,若是不一样的对象确产生了相同的hash值,也就是发生了Hash key相同致使冲突的状况,那么就在这个Hash key的地方产生一个链表,将全部产生相同hashcode的对象放到这个单链表上去,串在一块儿。 
2.比较两个对象的时候,首先根据他们的hashcode去hash表中找他的对象,当两个对象的hashcode相同,那么就是说他们这两个对象放在Hash表中的同一个key上,那么他们必定在这个key上的链表上。那么此时就只能根据Object的equal方法来比较这个对象是否equal。当两个对象的hashcode不一样的话,确定他们不能equal. 

============================================================   
改写equals时老是要改写hashCode 
============================================================ 
java.lang.Object中对hashCode的约定: 

   1. 在一个应用程序执行期间,若是一个对象的equals方法作比较所用到的信息没有被修改的话,则对该对象调用hashCode方法屡次,它必须始终如一地返回同一个整数。 
   2. 若是两个对象根据equals(Object o)方法是相等的,则调用这两个对象中任一对象的hashCode方法必须产生相同的整数结果。 
   3. 若是两个对象根据equals(Object o)方法是不相等的,则调用这两个对象中任一个对象的hashCode方法,不要求产生不一样的整数结果。但若是能不一样,则可能提升散列表的性能。  java

(如下的测试代码,我稍微修改过) 算法

import java.util.*;
public class AboutHashCode {

	public static void main(String[] args) {
		HashSet stringSet = new HashSet<V>();
		for(int i=0; i<10; i++)
		stringSet.add(new String("test"));//默认重写equals().hashcode()
									//产生相同的hashcode,并且equals返回true因此不加进去;
		System.out.println(stringSet.size());

		
		HashSet vSet = new HashSet<V>();
		for (int i = 0; i < 10; i++) {
			vSet.add(new V(i/2));
		}
		System.out.println(vSet.size());
	}

	public static class V {
	int i;
	public V(int i) {
		this.i = i;
	}
	public int getI() {
		return this.i;
	}
	public boolean equals(Object o) {
		V v = (V) o;
		System.out.print("hashcode相同的,而后才执行的equals()方法的!");
		System.out.println(v.getI() == this.i);
		return v.getI() == this.i;
	}
	//若是不重写,将会产生不一样的hashcode,因此能够加进set里面
	public int hashCode() {
		System.out.println("先执行hashCode()方法的!");
		return i;
	}
}
	
}
相关文章
相关标签/搜索