JAVA - hashcode与equals作用、关系

时间:2021-08-09 16:17:12
 
Hashcode的作用
  总的来说,Java中的集合(Collection)有两类,一类是List,再有一类是Set。前者集合内的元素是有序的,元素可以重复;后者元素无序,但元素不可重复。
       要想保证元素不重复,可两个元素是否重复应该依据什么来判断呢?这就是Object.equals方法了。但是,如果每增加一个元素就检查一 次,那么当元素很多时,后添加到集合中的元素比较的次数就非常多了。也就是说,如果集合中现在已经有1000个元素,那么第1001个元素加入集合时,它 就要调用1000次equals方法。这显然会大大降低效率。
       于是,Java采用了哈希表的原理。哈希算法也称为散列算法,是将数据依特定算法直接指定到一个地址上。这样一来,当集合要添加新的元素时,先调用这个元素的hashCode方法,就一下子能定位到它应该放置的物理位置上。如果这个位置上没有元素,它就可以 直接存储在这个位置上,不用再进行任何比较了;如果这个位置上已经有元素了,就调用它的equals方法与新元素进行比较,相同的话就不存了;不相同,也就是发生了Hash key相同导致冲突的情况,那么就在这个Hash key的地方产生一个链表,将所有产生相同hashcode的对象放到这个单链表上去,串在一起。所以这里存在一个冲突解决的问题(很少出现)。这样一来实际调用equals方法的次数就大大降低了,几乎只需要一两次。 
 
equal && 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. 
 
 
两个对象相等必须满足:
  • hashcode相等(Hash表中的同一个key上)>>equals()返回true(这个key上的链表上的同一位置)
 
1、如果两个对象相等,那么它们的hashCode值一定要相等;
2、如果两个对象的hashCode相等,它们并不一定相等。
 
改写equals时总是要改写hashCode :
  1. import java.util.*;
  2.  
  3. class V { 
  4.     int i; 
  5.     public V(int i){ 
  6.         this.i = i; 
  7.     } 
  8.     publicint getI(){ 
  9.         returnthis.i; 
  10.     } 
  11.    //如果不重写,将会产生不同的hashcode,所以可以加进set里面 
  12.     publicint hashCode(){ 
  13.         System.out.println("先执行hashCode()方法的!"); 
  14.         return i; 
  15.    }
  16.     public boolean equals(Object o){ 
  17.         V v =(V) o; 
  18.         System.out.print("hashcode相同的,然后才执行的equals()方法的!"); 
  19.         System.out.println(v.getI()==this.i); 
  20.         return v.getI()==this.i; 
  21.     } 
  22.    
  23.  
  24. publicclassTest{ 
  25.     publicstaticvoid main(String[] args){ 
  26.         HashSetset=newHashSet(); 
  27.         for(int i=0; i<10; i++) 
  28.         set.add(newString("test"));//默认重写hashcode() equals()
  29.                                     //产生相同的hashcode,而且equals返回true所以不加进去; 
  30.         System.out.println(set.size()); 
  31.         set.clear(); 
  32.  
  33.         for(int i =0; i <10; i++){ 
  34.             set.add(new V(1)); 
  35.         } 
  36.         System.out.println(set.size()); 
  37.     } 
  38. }