对几个通用的Java hashCode重写方案的一些思考和探讨

java中重写equals和hashCode方法 为什么要重写equals和hashCode方法,hashCode()和equals()定义在Object类中,这个类是所有java类的基类,所以所有的java类都继承这两个方法。 hashCode()方法被用来获取给定对象的唯一整数。这个整数被用来确定对象被存储在HashTable类似的结构中的位置。默认的,Object类的hashCode()方法返回这个对象存储的内存地址的编号。 阅读详情

在我们刚开始学习Java的时候就被教导,在编写类的时候,如果覆盖了Object的equals方法,那么必须要覆盖hashCode方法,并且如果两个对象用equals方法比较返回true,那么这两个对象hashCode返回的值也必须是相等的,并且对于同一个对象,equals方法需要比较的属性值没有被修改,那么每次调用hashCode返回的值应该是一致的。

hashCode主要是用于散列集合,通过对象hashCode返回值来与散列中的对象进行匹配,通过hashCode来查找散列中对象的效率为O(1),如果多个对象具有相同的hashCode,那么散列数据结构在同一个hashCode位置处的元素为一个链表,需要通过遍历链表中的对象,并调用equals来查找元素。这也是为什么要求如果对象通过equals比较返回true,那么其hashCode也必定一致的原因。

为对象提供一个高效的hashCode算法是一个很困难的事情。理想的hashCode算法除了达到本文最开始提到的要求之外,还应该是为不同的对象产生不相同的hashCode值,这样在操作散列的时候就完全可以达到O(1)的查找效率,而不必去遍历链表。假设散列中的所有元素的hashCode值都相同,那么在散列中查找一个元素的效率就变成了O(N),这同链表没有了任何的区别。

这种理想的hashCode算法,如果是为具体业务的对象去设计应该不是很难,比如很多的数据库映射对象都存在一个整形的id属性,这个id属性往往在整个系统中是唯一的,那么hashCode在重写的时候返回这个id的值就可以了,equals比较的时候也是去比较id的值,并且对象在从数据库初始化之后是不可变的,这样就完全达到了理想的情况。这些对象保存在散列中,查找效率会是完全的O(1),不需要遍历任何链表。

本文着重讨论的是通用的hashCode实现,所谓的通用就是适合Java中每一个对象的hashCode算法实现。每个类的结构不尽相同,要想产生一个适合所有场景的理想hashCode算法几乎是不可能的,要设计通用的hashCode算法,我们只能去不断接近理想的情况。下面是几种实现方式。

《Effective Java》中推荐的实现方式

Google首席Java架构师Joshua Bloch在他的著作《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计算,算法同上,
  java.util.Arrays.hashCode(long[])的具体实现:
?
1
2
3
4
5
6
7
8
9
10
11
12
public static int hashCode( long a[]) {
         if (a == null )
             return 0 ;
 
         int result = 1 ;
         for ( long element : a) {
             int elementHash = ( int )(element ^ (element >>> 32 ));
             result = 31 * result + elementHash;
         }
 
         return result;
}

Arrays.hashCode(...)只会计算一维数组元素的hashCOde,如果是多维数组,那么需要递归进行hashCode的计算,那么就需要使用Arrays.deepHashCode(Object[])方法。

3. 最后,要如同上面的代码,把每个域的散列码合并到result当中:result = 31 * result + elementHash;
4. 测试,hashCode方法是否符合文章开头说的基本原则,这些基本原则虽然不能保证性能,但是可以保证不出错。

这个算法存在这么几个问题需要探讨:
1. 为什么初始值要使用非0的整数?这个的目的主要是为了减少hash冲突,考虑这么个场景,如果初始值为0,并且计算hash值的前几个域hash值计算都为0,那么这几个域就会被忽略掉,但是初始值不为0,这些域就不会被忽略掉,示例代码:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import java.io.Serializable;
 
public class Test implements Serializable {
 
     private static final long serialVersionUID = 1L;
 
     private final int [] array;
 
     public Test( int ... a) {
         array = a;
     }
 
     @Override
     public int hashCode() {
         int result = 0 ; //注意,此处初始值为0
         for ( int element : array) {
             result = 31 * result + element;
         }
         return result;
     }
 
     public static void main(String[] args) {
         Test t = new Test( 0 , 0 , 0 , 0 );
         Test t2 = new Test( 0 , 0 , 0 );
         System.out.println(t.hashCode());
         System.out.println(t2.hashCode());
     }
 
}

如果hashCode中result的初始值为0,那么对象t和对象t2的hashCode值都会为0,尽管这两个对象不同。但如果result的值为17,那么计算hashCode的时候就不会忽略这些为0的值,最后的结果t1是15699857,t2是506447

2. 为什么每次需要使用乘法去操作result? 主要是为了使散列值依赖于域的顺序,还是上面的那个例子,Test t = new Test(1, 0)跟Test t2 = new Test(0, 1), t和t2的最终hashCode返回值是不一样的。

3. 为什么是31? 31是个神奇的数字,因为任何数n * 31就可以被JVM优化为 (n << 5) -n,移位和减法的操作效率要比乘法的操作效率高的多。

另外如果对象是不可变的,那么还推荐使用缓存的方式,在对象中使用一个单独的属性来存储hashCode的值,这样对于这个对象来说hashCode只需要计算一次就可以了。

?
1
2
3
4
5
6
7
8
9
10
11
12
private volatile int hashCode = 0 ;
 
@Override
public int hashCode() {
 
     int result = hashCode;
     if (result == 0 ) {
 
         ... //计算过程
     }
     return result;
}

注意,缓存属性必须是volatile的,这样可以在并发访问环境中保持内存可见性。否则会产生线程安全问题。

此外上面所提到的基本元素类型的hashCode计算,其算法同JDK中其包装器类型所覆盖的hashCode逻辑一致
java.lang.Long的hashCode实现:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/**
      * Returns a hash code for this {<a href="http://my.oschina.net/codeo" target="_blank" rel="nofollow">@code</a>  Long}. The result is
      * the exclusive OR of the two halves of the primitive
      * {<a href="http://my.oschina.net/codeo" target="_blank" rel="nofollow">@code</a>  long} value held by this {<a href="http://my.oschina.net/codeo" target="_blank" rel="nofollow">@code</a>  Long}
      * object. That is, the hashcode is the value of the expression:
      *
      * <blockquote>
      *  {<a href="http://my.oschina.net/codeo" target="_blank" rel="nofollow">@code</a>  (int)(this.longValue()^(this.longValue()>>>32))}
      * </blockquote>
      *
      * @return  a hash code value for this object.
      */
     public int hashCode() {
         return ( int )(value ^ (value >>> 32 ));
     }

java.lang.Float的hashCode实现:

?
1
2
3
4
5
6
7
8
9
10
11
12
/**
   * Returns a hash code for this {<a href="http://my.oschina.net/codeo" target="_blank" rel="nofollow">@code</a>  Float} object. The
   * result is the integer bit representation, exactly as produced
   * by the method {<a href="http://my.oschina.net/link1212" target="_blank" rel="nofollow">@link</a>  #floatToIntBits(float)}, of the primitive
   * {<a href="http://my.oschina.net/codeo" target="_blank" rel="nofollow">@code</a>  float} value represented by this {<a href="http://my.oschina.net/codeo" target="_blank" rel="nofollow">@code</a>  Float}
   * object.
   *
   * @return a hash code value for this object.
   */
  public int hashCode() {
      return floatToIntBits(value);
  }

java.lang.double的hashCode实现:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/**
   * Returns a hash code for this {<a href="http://my.oschina.net/codeo" target="_blank" rel="nofollow">@code</a>  Double} object. The
   * result is the exclusive OR of the two halves of the
   * {<a href="http://my.oschina.net/codeo" target="_blank" rel="nofollow">@code</a>  long} integer bit representation, exactly as
   * produced by the method {<a href="http://my.oschina.net/link1212" target="_blank" rel="nofollow">@link</a>  #doubleToLongBits(double)}, of
   * the primitive {<a href="http://my.oschina.net/codeo" target="_blank" rel="nofollow">@code</a>  double} value represented by this
   * {<a href="http://my.oschina.net/codeo" target="_blank" rel="nofollow">@code</a>  Double} object. That is, the hash code is the value
   * of the expression:
   *
   * <blockquote>
   *  {<a href="http://my.oschina.net/codeo" target="_blank" rel="nofollow">@code</a>  (int)(v^(v>>>32))}
   * </blockquote>
   *
   * where {<a href="http://my.oschina.net/codeo" target="_blank" rel="nofollow">@code</a>  v} is defined by:
   *
   * <blockquote>
   *  {<a href="http://my.oschina.net/codeo" target="_blank" rel="nofollow">@code</a>  long v = Double.doubleToLongBits(this.doubleValue());}
   * </blockquote>
   *
   * @return  a {<a href="http://my.oschina.net/codeo" target="_blank" rel="nofollow">@code</a>  hash code} value for this object.
   */
  public int hashCode() {
      long bits = doubleToLongBits(value);
      return ( int )(bits ^ (bits >>> 32 ));
  }



org.apache.commons.lang.builder.HashCodeBuilder的实现

org.apache.commons.lang.builder.HashCodeBuilder能够通过反射机制来自动计算对象的hashCode值。其核心方法是静态方法:reflectionHashCode,这个方法有多个重载的版本,这些重载版本最终都是调用的  int reflectionHashCode(  intinitialNonZeroOddNumber,  int multiplierNonZeroOddNumber, Object object,

            boolean testTransients, Class reflectUpToClass, String[] excludeFields)

其余的版本只是提供不同的默认参数,从而简化了构建的过程。比如:

?
1
2
3
public static int reflectionHashCode(Object object) {
         return reflectionHashCode( 17 , 37 , object, false , null , null );
}

然后构建的过程是这样的,除了指定过滤的,比如transient属性、excludeFields指定的属性之外,会遍历其它的类属性,然后通过反射的方式获取属性值,如果属性是数组,则会遍历数组,否则会调用属性的hashCode, 如果是多维数组,会去递归取hashCode值,对单个属性计算hash值的代码如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
public HashCodeBuilder append(Object object) {
         if (object == null ) {
             iTotal = iTotal * iConstant;
 
         } else {
             if (object.getClass().isArray()) {
                 // 'Switch' on type of array, to dispatch to the correct handler
                 // This handles multi dimensional arrays
                 if (object instanceof long []) {
                     append(( long []) object);
                 } else if (object instanceof int []) {
                     append(( int []) object);
                 } else if (object instanceof short []) {
                     append(( short []) object);
                 } else if (object instanceof char []) {
                     append(( char []) object);
                 } else if (object instanceof byte []) {
                     append(( byte []) object);
                 } else if (object instanceof double []) {
                     append(( double []) object);
                 } else if (object instanceof float []) {
                     append(( float []) object);
                 } else if (object instanceof boolean []) {
                     append(( boolean []) object);
                 } else {
                     // Not an array of primitives
                     append((Object[]) object);
                 }
             } else {
                 iTotal = iTotal * iConstant + object.hashCode();
             }
         }
         return this ;
     }

这里要小心,因为它是直接调用属性对象的hashCode,如果是基本类型,那么就会调用包装器中提供的hashCode方法,如果是引用类型,那么需要仔细检查引用类型的hashCode方法,以免产生违反hashCode基本原则的情况。

然后剩下的计算过程,同Effective Java中描述的基本类似,不过这里的hash初值和乘数因子可以自己来设置,默认的情况是使用了17 和 37两个互质数。

HashCodeBuilder最大好处是使用方便,一行代码就能搞定hashCode的重写问题,并且让代码很清晰,但是它有这么几个值得注意的地方:

1. 使用反射会对程序的性能造成影响,不过Java反射机制为了把性能影响降到最低,对类似getFields()之类的操作都采用了Cache策略,对一般的程序而言,这些性能开销往往可以忽略不计。另外如果使用的是不可变对象,那么强烈建议把hashCode Cache住,这样可以极大的提高hashCode计算的性能。

2. 因为默认会处理所有的field(除了transient修饰的field),所以一定要测试是否违反hashCode的基本原则(为了保障基本原则的正确,建议跟org.apache.commons.lang.EqualsBuilder搭配使用),尤其是当类的域中包含引用类型的时候,一定要递归检查引用类型的hashCode.

链式的HashCodeBuilder

最后结合Effective Java中提供的算法编写一个链式的HashCode生成器:
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
import java.util.Arrays;
 
/**
  * 一个链式调用的通用hashCode生成器
  *
  * <a href="http://my.oschina.net/arthor" target="_blank" rel="nofollow">@author</a>  hongze.chi@gmail.com
  *
  */
public final class HashCodeHelper {
 
     private static final int multiplierNum = 31 ;
 
     private int hashCode;
 
     private HashCodeHelper() {
         this ( 17 );
     }
 
     private HashCodeHelper( int hashCode) {
         this .hashCode = hashCode;
     }
 
     public static HashCodeHelper getInstance() {
         return new HashCodeHelper();
     }
 
     public static HashCodeHelper getInstance( int hashCode) {
         return new HashCodeHelper(hashCode);
     }
 
     public HashCodeHelper appendByte( byte val) {
         return appendInt(val);
     }
 
     public HashCodeHelper appendShort( short val) {
         return appendInt(val);
     }
 
     public HashCodeHelper appendChar( char val) {
         return appendInt(val);
     }
 
     public HashCodeHelper appendLong( long val) {
         return appendInt(( int ) (val ^ (val >>> 32 )));
     }
 
     public HashCodeHelper appendFloat( float val) {
         return appendInt(Float.floatToIntBits(val));
     }
 
     public HashCodeHelper appendDouble( double val) {
         return appendLong(Double.doubleToLongBits(val));
     }
 
     public HashCodeHelper appendBoolean( boolean val) {
         return appendInt(val ? 1 : 0 );
     }
 
     public HashCodeHelper appendObj(Object... val) {
         return appendInt(Arrays.deepHashCode(val));
     }
 
     public HashCodeHelper appendInt( int val) {
         hashCode = hashCode * multiplierNum + val;
         return this ;
     }
 
     public int getHashCode() {
         return this .hashCode;
     }
}

通过这种链式调用的方式,没有反射的开销,另外可以比较方便的选择要参与计算的属性,代码也比较清晰,但是如果参与计算的属性值过多,那么会造成调用链过长的情况。为保持代码的整洁,也可以分多个链来调用。示例代码:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import java.io.Serializable;
 
public class Test implements Serializable{
 
     private static final long serialVersionUID = 1L;
 
     private final int [] array;
 
     public Test( int ... a) {
         array = a;
     }
 
     @Override
     public int hashCode() {
         HashCodeHelper hashCodeHelper = HashCodeHelper.getInstance();
         hashCodeHelper.appendInt(array[ 0 ]).appendInt(array[ 1 ]).appendInt(array[ 2 ]);
         hashCodeHelper.appendInt(array[ 3 ]).appendInt(array[ 4 ]).appendInt(array[ 5 ]);
         return hashCodeHelper.getHashCode();
     }
}

equals和hashcode方法重写 在 Java 中,当你需要来判断两个对象是否相等时,就需要重写equals和hashCode方法。 阅读详情

相关推荐

SimpleITK图像基础(一)——3D Resampling

文章目录前言基于SimpleITK进行实现 前言 进入深度学习网络之前需要进行统一数据集,这个时候需要对这些数据集进行重新采样,即假设各向同性体素并重新定向它们,以便可以读取所有图像的像素矩阵。 在将方位变换成一致时,可以用DICOMOrientImageFilter过滤器,可以将 DesiredCoordinateOrientation设置为你想要变换的方位,它将计算出所需的置换顺序并根据需要执行翻转以接近所需方向。 基于SimpleITK进行实现 workflow如下: step 1:首先运行DICOM

YYY_77的博客 2019

转载:对几个通用的Java hashCode重写方案的一些思考和探讨

在我们刚开始学习Java的时候就被教导,在编写类的时候,如果覆盖了Object的equals方法,那么必须要覆盖hashCode方法,并且如果两个对象用equals方法比较返回true,那么这两个对象hashCode返回的值也必须是相等的,并且对于同一个对象,equals方法需要比较的属性值没有被修改,那么每次调用hashCode返回的值应该是一致的。 hashCode主要是用于散列集合,通...

moisen的专栏 253

Appsflyer S2S事件上报实战:从参数获取到避坑指南(附Firebase对比)

本文详细解析了Appsflyer S2S事件上报的实战技巧,包括核心参数获取、测试环境搭建、生产环境最佳实践以及高级场景处理。通过对比Firebase的事件上报机制,帮助开发者高效避坑并优化数据上报流程,提升应用分析与营销效果。

egg99的博客 884

java hashcode机制,使用commons-lang.jar包以及反射机制实现javabean的equals,hashCode和toString三个方法重写...

在实际项目中,有时需要对javabean的equals,hashCode和toString三个方法重写,一般情况下会选择手写,这样比较繁琐,另外一种方式是通过反射机制就可以完成,这样就显得更为简单。1.手写借用其他博客中手写代码案例1package per.jone;2import java.util.Date;3import org.apache.commons.lang.builder.Equ...

weixin_39530149的博客 245

手把手教你配置C6678的SPI启动:从NorFlash烧写到多核加载的完整流程

本文详细介绍了TMS320C6678多核DSP的SPI启动全流程,包括硬件准备、镜像文件生成与转换、NorFlash烧写与验证、多核启动同步机制以及常见问题排查。通过实战演示,帮助开发者高效配置SPI启动模式,解决启动失败、多核同步异常等问题,提升嵌入式系统开发效率。

weixin_27076351的博客 150

游戏数据训练世界模型:AI物理规律学习与仿真应用实践

世界模型作为理解现实世界动态的AI工具,通过多模态数据学习物理和空间属性来预测未来状态。其核心原理在于从环境交互中提取物理规律,技术价值体现在能够安全、低成本地训练AI系统应对复杂场景。在应用层面,游戏数据因其结构化环境和内置物理引擎,成为世界模型训练的优质素材。游戏世界中的物体交互、运动轨迹等数据天然包含现实物理规律,特别适合训练物理AI。本文以General Intuition公司获得3.2亿美元融资为切入点,深入探讨游戏数据在世界模型训练中的技术实现路径,涵盖数据提取管道构建、多模态数据融合方法,以及

weixin_29056865的博客 366

重写equals(),hashCode()方法

```java @Override public int hashCode() { return HashCodeBuilder.reflectionHashCode(this,false); } @Override public boolean equals(Object obj) { return EqualsBuilder.reflectionEquals(this,obj); }

huozhezi的博客 134

C#实战:如何用winmm.dll打造毫秒级高精度定时器(附完整代码)

本文详细介绍了在C#中利用winmm.dll实现毫秒级高精度定时器的完整方案。针对.NET内置定时器精度不足的问题,通过调用timeSetEvent等原生API,提供了超越系统时钟中断周期的精准定时能力。文章包含核心原理剖析、完整的封装类代码以及音视频处理、游戏开发等场景下的实战应用与性能调优指南。

ujm5678901的博客 689

去重 属性_写了这么多代码,你还不会去重实体类 ?

写了这么多代码,你还不会去重实体类 ?引言日常 coding 中经常遇到实体的集合,需要进行去重,一般都是交给java来执行,效率快,还不用操作数据库,之前听朋友说面试别人,经常有问到这个问题,其实很简单的问题.可是还是有一部分答不上来,也有一部分答上来说重写equals与hashCode,虽然说说的是对的,但是用伪代码写出来的时候,还是写不出来Set在插入数据判断依据Set在插入数据时, 会先比...

weixin_42119989的博客 205

MATLAB控制信号发生器(USB-GPIB-HS)GPIB仪器控制教程(含matlab代码)

自动化测试时需要自动产生信号,通过matlab控制信号发生器的频率与功率,以实现自动化信号生成输出

qq_43686057的博客 1606

TC3XX - MCAL知识点(一):新建Tc3xx EB-tresos工程

基于EB-tresos建立Hightec或者Tasking工程的时候,第一个步骤就是需要新建一个EB-tresos的工程,本文记录一下如何新建一个EB-tresos工程,以及对其进行简单的操作。那么Tc3xx的MCAL包含哪些内容呢?

梦想技术家 2966

jdk 里面的int、string、类、复合类的 HashCode 方法

目录 Integer 核心代码 String 核心代码 类 举例 重写 equals 结果 重写 hashCode 方法 结果 参考文章 Integer 核心代码 /** * Returns a hash code for this {@code Integer}. * * @return a hash code value f...

resemble的博客 1455

华为OD新系统机试真题 - 操作历史管理器的撤销/重做能力

华为OD机试新系统真题【操作历史管理器的撤销/重做能力】,提供C语言、Java、C++、Python、Go、JavaScript源码实现,并提供完整思路讲解,以及在线OJ模拟做题。华为OD机试真题【操作历史管理器的撤销/重做能力】

qq_45776114的博客 863

【Java】对几个通用的hashCode重写方案的一些思考和探讨

在我们刚开始学习Java的时候就被教导,在编写类的时候,如果覆盖了Object的equals方法,那么必须要覆盖hashCode方法,并且如果两个对象用equals方法比较返回true,那么这两个对象hashCode返回的值也必须是相等的,并且对于同一个对象,equals方法需要比较的属性值没有被修改,那么每次调用hashCode返回的值应该是一致的。 hashCode主要是用于散列集合,通过对

u011494050的专栏 1606

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

Java 细品 重写equals方法 和 hashcode 方法

前言 在我们需要比较对象是否相等时,我们往往需要采取重写equals方法和hashcode方法。 该篇,就是从比较对象的场景结合通过代码实例以及部分源码解读,去跟大家品一品这个重写equals方法和hashcode方法。 正文 场景: 我们现在需要比较两个对象 Pig 是否相等 。 而Pig 对象里面包含 三个字段, name,age,nickName ,我们现在只需要认为如果两个pig对象的name名字和age年龄一样,那么这两个pig对象就是一样的,nic...

默默不代表沉默 6213

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

在java中为什么重写equals要重写hashcode

equals() 方法用于比较两个对象是否相等,而 hashCode() 方法用于获取对象的哈希码在 Java 中,如果两个对象通过 equals() 方法判断为相等,则它们的 hashCode() 方法必须返回相同的值。这是因为在使用哈希表(如 HashMap、HashSet)等数据结构时,会先根据对象的哈希码确定存储位置,然后再使用 equals() 方法进行比较来确保唯一性。

weixin_62988359的博客 4836

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

java中什么时候需要重写equals和hashCode方法,以及为什么重写:

1.使用Object默认的equals()和hashCode()方法: public class HashCode { private String name; private int age; public HashCode(String name,int age) { this.name = name; this.age = age...

weixin_42493179的博客 5666

重写equals和hashcode

1.重写equals1.1重写equals原因(1)Object类中equals方法比较的是两个对象的引用地址,只有对象的引用地址指向同一个地址时,才认为这两个地址是相等的,否则这两个对象就不想等。 (2)如果有两个对象,他们的属性是相同的,但是地址不同,这样使用equals()比较得出的结果是不相等的,而我们需要的是这两个对象相等,因此默认的equals()方法是不符合我们的要求的,这个时候我们就需要对equals()方法进行重写以满足我们的预期结果。 (3)在java的集合框架中需要用到equals()

wdnn_wza的博客 5942

为什么要重写hashCode()方法

一.引言 首先 hashCode() 方法被设计在 Object 类中,说明是希望所有的对象都能实现该方法,该方法是会返回一个对应于当前对象的一个整数,之所以所有对象都实现该方法是为了将来对象在查找时变得快捷。 Java中的集合类 hashMap、hashSet 底层的实现都是哈希表,之所以采用哈希表,是因为他能克服链表和二叉树等数据结构在查询上的低效率问题,哈希表的存储就是根据对象的哈希值,以此确定他的存储位置。 但是,仅仅通过 hashcode() 并不能将所有对象区分开来,有可能会出现对象不同,ha

Welcome To kua_fuXz's Blog 5912

为什么重写 equals 还要重写 hashcode?

重写equals()和hashCode()的核心目的是保证对象在哈希表中行为的正确性。若忽略这一原则,会导致集合类无法正常工作,甚至引发难以调试的逻辑错误。一致性equals()和hashCode()需基于相同的字段。性能优化:合理的哈希算法能减少冲突,提升集合效率。版权声明:本博客内容为原创,转载请保留原文链接及作者信息。参考文章面试官:重写 equals 时为什么一定要重写 hashCode?- 腾讯云为什么重写equals()方法时必须重写hashCode()方法?

ning的博客 1981

重写hashCode也得重写方法?

这是一个非常经典的问题,我们先从运算符“==”来说明一下。

s44359487yad的博客 1717

Java 细品 重写equals方法 和 hashcode 方法

《一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码》,点击传送门,即可获取! public Integer getAge() {return age;}public void setAge(Integer age) {this.age = age;}public String getNickName() {return nickName;}public void setNickName(String nickName) {this.nickName = nickName;}}可以看到

2401_84092832的博客 1529

java重写hashcode_正确重写hashCode的办法

——————————————————————————————————————————正确重写hashCode的办法[1]. hashCode重写成相同的值的缺点将所有对象的hashCode都返回一样的值是不科学的。比如a1和a3这两个根本不同的对象,就没有必要去比较equals,增加无谓的计算量。所以应该对象本身的内容(属性)来重写hashCode。一旦两个对象内部不一样,就直接判定出hashC...

weixin_29352517的博客 8995

重写hashcode

hashCode() 1. 何为hashcode? hashCode() 的作用是获取哈希码,也称为散列码;它实际上是返回一个 int 整数。这个哈希码的作用是确定该对象在哈希表中的索引位置。散列表存储的是键值对(key-value),它的特点是:能根据“键”快速的检索出对应的“值”。这其中就利用到了散列码!(可以快速找到所需要的对象)。在散列表中 hashCode() 的作用是获取对象的散列码,进而确定该对象在散列表中的位置。 hashCode()定义在 JDK 的 Object 类中,这就意味着 Jav

weixin_44321790的博客 6306
上一篇: hashCode与equals的区别与联系
下一篇: Quartz任务监控管理
wangshfa
博客等级 码龄17年 117粉丝 2原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值