【源码分析】Object中的“鸡肋“函数

2023-11-04 05:44

本文主要是介绍【源码分析】Object中的“鸡肋“函数,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

java中的“鸡肋”代码

返回对象的散列码值。支持此方法是为了使用哈希表,例如java.util.HashMap提供的哈希表。

  • 具体使用可以看【源码分析】HashMap真源码阅读

hashCode的总契约是:

  • 在Java应用程序的执行过程中,只要在同一对象上多次调用hashCode方法,hashCode方法必须始终返回相同的整数,前提是对象上用于相等比较的信息没有被修改。该整数不必在应用程序的一次执行与另一次执行之间保持一致。
  • 如果根据equals(Object)方法两个对象相等,那么对这两个对象中的每一个调用hashCode方法必须产生相同的整数结果。
  • 根据equals(Object)方法,如果两个对象不相等,则不要求对这两个对象中的每一个调用hashCode方法必须产生不同的整数结果。然而,程序员应该意识到,为不相等的对象生成不同的整数结果可能会提高哈希表的性能。

在合理可行的情况下,由Object类定义的hashCode方法确实为不同的对象返回不同的整数。(这通常通过将对象的内部地址转换为整数来实现,但是Java™编程语言不需要这种实现技术。)

  • 同一对象调用多次调用hashCode方法必须始终返回相同的整数,且整数不必在应用程序的一次执行与另一次执行之间保持一致
  • 前提是对象上用于相等比较的信息没有被修改,这句我的理解是equals方法按照注释上实现。
  • equals 两对象相等,hashCode方法必须产生相同的整数结果
  • equals 两对象不相等,hashCode方法必须产生不相同的整数结果

注:理论上不同值计算hash是可以相同的,作者也解释为什么一定要hashcode方法生成结果不同:为不相等的对象生成不同的整数结果可能会提高哈希表的性能。

回忆一下Hash函数设计的基本要求(完美满足,Hashtable,HashMap可以直接用了):

  • 散列函数计算得到的散列值是一个非负整数;
  • 如果 key1 = key2,那 hash(key1) == hash(key2);
  • 如果 key1 ≠ key2,那 hash(key1) ≠ hash(key2)。(往往这个条件很难办到,key不同可能出现相同的散列值,于是出现散列冲突)
public native int hashCode();

指示其他对象是否“等于”此对象。
equals方法在非空对象引用上实现等价关系:

  • 它是自反的:对于任何非空的引用值x, x.x equals(x)应该返回true。
  • 它是对称的:对于任何非空引用值x和y,当且仅当y.equals(x)返回true时,x.equals(y)应该返回true。
  • 它是可传递的:对于任何非空引用值x, y和z,如果x.equals(y)返回true并且y.equals(z)返回true,则x.equals(z)应该返回true。
  • 它是一致的:对于任何非空引用值x和y,如果不修改对象上的相等比较中使用的信息,则多次调用x.equals(y)一致地返回true或一致地返回false。
  • 对于任何非空的引用值x, x.equals(null)应该返回false。

Object类的equals方法在对象上实现了最具区别性的可能的等价关系;也就是说,对于任何非空引用值x和y,当且仅当x和y引用同一对象(x == y的值为true)时,此方法返回true。

  • 当且仅当x和y引用同一对象为true,因此,重写次方法第一步就应该实现if (this == object) { return true; }

请注意,每当覆盖hashCode方法时,通常都需要覆盖该方法,以便维护hashCode方法的一般契约,该契约规定相等的对象必须具有相等的哈希码。

public boolean equals(Object obj) {return (this == obj);
}

hashCode和equals小结

hashCode实现约定:

  • equals 两对象相等,hashCode方法必须产生相同的整数结果
  • equals 两对象不相等,hashCode方法必须产生不相同的整数结果

注意:

  • 每当重写hashCode方法时,通常都需要重写equals
  • == 在基本数据类型:值内容, 引用类型时:地址
  • equals 重写:值内容 , equals不重写:地址

不同类型hashCode和equals对比

这篇关于【源码分析】Object中的“鸡肋“函数的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/343641

相关文章

Go标准库常见错误分析和解决办法

《Go标准库常见错误分析和解决办法》Go语言的标准库为开发者提供了丰富且高效的工具,涵盖了从网络编程到文件操作等各个方面,然而,标准库虽好,使用不当却可能适得其反,正所谓工欲善其事,必先利其器,本文将... 目录1. 使用了错误的time.Duration2. time.After导致的内存泄漏3. jsO

Kotlin 作用域函数apply、let、run、with、also使用指南

《Kotlin作用域函数apply、let、run、with、also使用指南》在Kotlin开发中,作用域函数(ScopeFunctions)是一组能让代码更简洁、更函数式的高阶函数,本文将... 目录一、引言:为什么需要作用域函数?二、作用域函China编程数详解1. apply:对象配置的 “流式构建器”最

Python实现无痛修改第三方库源码的方法详解

《Python实现无痛修改第三方库源码的方法详解》很多时候,我们下载的第三方库是不会有需求不满足的情况,但也有极少的情况,第三方库没有兼顾到需求,本文将介绍几个修改源码的操作,大家可以根据需求进行选择... 目录需求不符合模拟示例 1. 修改源文件2. 继承修改3. 猴子补丁4. 追踪局部变量需求不符合很

Spring事务中@Transactional注解不生效的原因分析与解决

《Spring事务中@Transactional注解不生效的原因分析与解决》在Spring框架中,@Transactional注解是管理数据库事务的核心方式,本文将深入分析事务自调用的底层原理,解释为... 目录1. 引言2. 事务自调用问题重现2.1 示例代码2.2 问题现象3. 为什么事务自调用会失效3

找不到Anaconda prompt终端的原因分析及解决方案

《找不到Anacondaprompt终端的原因分析及解决方案》因为anaconda还没有初始化,在安装anaconda的过程中,有一行是否要添加anaconda到菜单目录中,由于没有勾选,导致没有菜... 目录问题原因问http://www.chinasem.cn题解决安装了 Anaconda 却找不到 An

Spring定时任务只执行一次的原因分析与解决方案

《Spring定时任务只执行一次的原因分析与解决方案》在使用Spring的@Scheduled定时任务时,你是否遇到过任务只执行一次,后续不再触发的情况?这种情况可能由多种原因导致,如未启用调度、线程... 目录1. 问题背景2. Spring定时任务的基本用法3. 为什么定时任务只执行一次?3.1 未启用

Android Kotlin 高阶函数详解及其在协程中的应用小结

《AndroidKotlin高阶函数详解及其在协程中的应用小结》高阶函数是Kotlin中的一个重要特性,它能够将函数作为一等公民(First-ClassCitizen),使得代码更加简洁、灵活和可... 目录1. 引言2. 什么是高阶函数?3. 高阶函数的基础用法3.1 传递函数作为参数3.2 Lambda

C++中::SHCreateDirectoryEx函数使用方法

《C++中::SHCreateDirectoryEx函数使用方法》::SHCreateDirectoryEx用于创建多级目录,类似于mkdir-p命令,本文主要介绍了C++中::SHCreateDir... 目录1. 函数原型与依赖项2. 基本使用示例示例 1:创建单层目录示例 2:创建多级目录3. 关键注

C++ 各种map特点对比分析

《C++各种map特点对比分析》文章比较了C++中不同类型的map(如std::map,std::unordered_map,std::multimap,std::unordered_multima... 目录特点比较C++ 示例代码 ​​​​​​代码解释特点比较1. std::map底层实现:基于红黑

C++中函数模板与类模板的简单使用及区别介绍

《C++中函数模板与类模板的简单使用及区别介绍》这篇文章介绍了C++中的模板机制,包括函数模板和类模板的概念、语法和实际应用,函数模板通过类型参数实现泛型操作,而类模板允许创建可处理多种数据类型的类,... 目录一、函数模板定义语法真实示例二、类模板三、关键区别四、注意事项 ‌在C++中,模板是实现泛型编程