equals的hashcode,hashcode和equals的区别 简书

  equals的hashcode,hashcode和equals的区别 简书

  Java的基类对象提供了一些方法,其中equals()方法用于判断两个对象是否相等,hashCode()方法用于计算对象的哈希代码。Equals()和hashCode()不是最终方法,两者都可以被覆盖。

  如何解决写爬虫IP受阻的问题?立即使用。

  本文介绍了使用和改写这两种方法时应注意的一些问题。

  一、equal()方法

  Object类中的equals()方法实现如下:

  公共布尔等于(对象对象){

  return(this==obj);

  }从这个实现可以看出,Object class的实现采用了区分度最高的算法,即只要两个对象不是同一个对象,那么equals()就必须返回false。

  虽然我们可以在定义类时覆盖equals()方法,但是有一些注意事项;JDK描述了实现equals()方法时应该遵守的约定:

  (1)自反性:x.equals(x)必须返回true。

  (2)对称性:x.equals(y)和y.equals(x)的返回值必须相等。

  (3)传递性:如果x.equals(y)为真,y.equals(z)为真,那么x.equals(z)一定为真。

  (4)一致性:如果equals()中对象X和Y使用的信息没有变化,那么x.equals(y)的值总是相同的。

  (5)非空:如果x不为空,y为空,则x.equals(y)必须为假。

  二、hashCode()方法

  1、Object的hashCode()

  Object类中hashCode()方法的声明如下:

  public native int hashCode();可以看出hashCode()是原生方法,返回值类型是shaping这个原生方法实际上是将对象在内存中的地址作为哈希代码返回,这样可以保证不同对象的返回值是不同的。

  类似于equals()方法,hashCode()方法可以被覆盖。JDK解释了hashCode()方法的作用以及实现时的注意事项:

  (1)hashCode()在哈希表中工作,比如java.util.HashMap

  (2)如果equals()中对象使用的信息都没有改变,那么hashCode()的值总是相同的。

  (3)如果用equals()方法判断两个对象相等,hashCode()方法也应该相等。

  (4)如果用equals()方法判断两个对象不相等,不要求hashCode()也一定不相等;但是,开发人员应该认识到,哈希表的性能可以通过不相等的对象产生不同的hashCode来提高。

  2、hashCode()的作用

  一般来说,hashCode()在哈希表中起作用,比如HashSet、HashMap等。

  当我们将一个object对象添加到哈希表(如HashSet、HashMap等)时。),我们首先调用hashCode()方法计算对象的hash码,通过它可以直接定位对象在哈希表中的位置(一般情况下hash码结转哈希表大小)。如果这个位置没有对象,可以直接把对象插入这个位置;如果这个位置有对象(可能有多个对象,用链表实现),调用equals()方法比较这些对象是否等于对象,如果相等,则不需要保存对象;如果没有,将该对象添加到链表中。

  这就解释了为什么equals()相等,则hashCode()必须相等。如果两个对象equals()相等,那么它们在一个哈希表中应该只出现一次(比如HashSet、HashMap等。);如果hashCode()不相等,那么它们将被散列到哈希表中的不同位置,这将出现不止一次。

  实际上,在JVM中,加载的对象在内存中包括三个部分:对象头、实例数据和填充。其中,对象头包括指向对象类型的指针和标记字,以及MarkWord中除了包含对象的GC分代年龄信息、加锁状态信息外,还包括了对象的hashcode;实例数据是对象真正存储的有效信息;填充只是作为一个占位符,因为HotSpot要求对象的起始地址必须是8字节的整数倍。

  

三、String中equals()和hashCode()的实现

   String类中的相关实现代码如下:

  私有最终字符值[];

  私有int哈希;//默认为0

  公共布尔等于(对象与对象){

  if (this==anObject) {

  返回true

  }

  if(字符串的对象实例){

  String another String=(String)an object;

  int n=value.length

  if(n==another string . value . length){

  char v1[]=值;

  char v2[]=another string . value;

  int I=0;

  而(n -!=0) {

  if (v1[i]!=v2[i])

  返回false

  我;

  }

  返回true

  }

  }

  返回false

  }

  public int hashCode() {

  int h=hash

  if (h==0 value.length 0) {

  char val[]=value;

  for(int I=0;i value.lengthi ) {

  h=31 * h val[I];

  }

  hash=h;

  }

  返回h;

  }通过代码可以看到以下几点:

  1.String的数据是final,即String对象一旦创建,就不能修改;如String s= hellos= world语句,当执行s=world 时,不是string对象的值更改为 world ,而是创建一个新的String对象,s引用指向新对象。

  2.String类将hashCode()的结果缓存为一个哈希值,以提高性能。

  3.String对象equals()相等的条件是,它们都是长度相同、字符串值完全相同的String对象;它们不需要是相同的对象。

  4.String的hashCode()的计算公式为:s [0] * 31 (n-1) s [1] * 31 (n-2).标准[名词]1

  在hashCode()的计算中使用数字31的原因如下:

  1.使用质数计算散列码。因为素数的特性,它乘以其他数后,计算结果唯一的概率更大,哈希冲突的概率更小。

  2.使用的素数越大,哈希碰撞的概率越小,但计算速度越慢;31是哈希碰撞和性能的折中,实际上是实验观察的结果。

  3.JVM会自动优化31: 31 * i==(i 5)-i

  

四、如何重写hashCode()

  本节首先介绍重写hashCode()方法时应遵循的原则,然后介绍一般的hashCode()重写方法。

  1、重写hashcode()的原则

  从前面的描述中,我们知道重写hashCode需要遵循以下原则:

  (1)如果equals()方法被覆盖,检查条件“如果两个对象被equals()方法判断为相等,hashCode()方法也应该相等”是否成立,如果不成立,重写hashCode()方法。

  (2)2)hashCode()方法不能太简单,否则哈希冲突太多。

  (3)3)hashCode()方法不能太复杂,否则计算复杂度太高,影响性能。

  2、hashCode()重写方法

  755-79000提出了一种简单通用的hashCode算法。

  a、初始化一个整形变量,给这个变量赋一个非零常数值,比如int result=17

  b、选择equals方法中所有用于比较的字段(之所以只选择equals()中使用的字段,是为了保证上述原则的第1条),然后计算每个字段的属性:

  (1)如果是布尔值,计算f?1:0

  (2)如果是byte\char\short\int,计算(int) f。

  (3)如果是长整型值,计算(int) (f (f 32))

  (4)如果是浮点值,则计算float.floatpointbits (f)

  (5)如果是double值,计算Double.doubleToLongBits(f),然后返回的结果是long,再用规则(3)处理long得到int。

  (6)如果是对象应用,如果equals方法中采用递归调用的比较方法,那么hashCode中也采用递归调用hashCode的方法。否则,您需要计算该字段的范式。例如,当该字段的值为null时,hashCode值为0。

  (7)如果是数组,那么每个元素都需要作为一个单独的域来对待。Java.util.Arrays.hashCode方法包括八种基本类型数组和引用数组的hashCode计算。算法同上。

  c、最后将各个域的哈希码合并到对象的哈希码中。

  下面的例子说明了这一点。在这个例子中,Person类覆盖了equals()方法和hashCode()方法。因为equals()方法中只使用了姓名和年龄字段,所以hashCode()方法中只计算姓名和年龄字段。

  对于String类型的域名,直接使用String的hashCode()方法;对于int类型的age字段,直接使用其值作为字段的哈希。

  公共类人员{

  私有字符串名称;

  私人年龄;

  私有布尔性别;

  公共人物(){

  super();

  }

  公共字符串getName() {

  返回名称;

  }

  public void setName(字符串名){

  this.name=name

  }

  public int getAge() {

  回归年龄;

  }

  公共无效存储(整数){

  this.age=年龄;

  }

  public boolean isGender() {

  返回性别;

  }

  public void setGender(布尔性别){

  this.gender=性别;

  }

  @覆盖

  公共布尔等于(对象另一个){

  如果(这==另一个){

  返回真实的

  }

  如果(另一个人的实例){

  Person另一个人=(人)另一个;

  if (this.getName().等于(另一个人。getname())这个。getage()==另一个人。getage()){

  返回真实的

  }否则{

  返回错误的

  }

  }

  返回错误的

  }

  @覆盖

  public int hashCode() {

  int hash=17

  hash=hash * 31 getName().hashCode();

  hash=hash * 31 getAge();

  返回哈希;

  }

  }推荐教程:java教程以上就是等于()方法和哈希码()方法(详细介绍)的详细内容,更多请关注我们其它相关文章!

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: