- 浏览: 188330 次
- 性别:
- 来自: 上海
文章分类
最新评论
"哈希表"数据结构 (参考了SUN官方文档以及无数的网上资料做出的个人总结)
在集合框架中 HashSet Hashtable HashMap 都使用了哈希表的形式来存储数据;保证数据唯一的方法;hashCode() & equals();
关于hashCode:
初学者可以粗略的将 hashCode 的值理解为内存地址值,但这不是绝对物理地址,它是经过哈希算法转成的 int 值;
哈希码并不是完全唯一的,它是一种算法,尽量使不同对象拥有不同的哈希码,作为身份的标识
hashCode()的几种算法
1)Object类的hashCode.返回对象的内存地址经过处理后的结构,由于每个对象的内存地址都不一样,所以哈希码也不一样。
2)String类的hashCode.根据String类包含的字符串的内容,根据一种特殊算法返回哈希码,只要字符串所在的堆空间相同,返回的哈希码也相同。
3)Integer类,返回的哈希码就是Integer对象里所包含的那个整数的数值,
例如Integer i1=new Integer(100),i1.hashCode的值就是100 。由此可见,2个一样大小的Integer对象,返回的哈希码也一样。
Object 的哈希码是唯一的,而当对象所对应的类重写了hashCode()方法时,就不一定了。即使两个对象equals为false,也有可能产生相同的哈希码。
例如,字符串"BB"和"Aa"的euqals方法比较结果肯定不相等,但它们的hashCode方法返回值却相等。(都是2112)
但可以确定的是:如果a.equals(b)为 true,a和b必须有相同的哈希码。(规定)
除非你刻意修改参与hashCode计算的字段,如后文注意事项(2)中所述,会导致内存泄露。(将这种行为视为失误或恶意行为)
哈希码的作用:
"哈希码就是对象的身份证" "equals比较相当于匹配对象的DNA" 例如:确定一个人的身份,查身份证号显然要比对比DNA简单得多
hashCode能够"提高哈希表集合的性能"-->快速地定位对象
hashCode算法提高查找的效率,这种方式将集合分成若干个存储区域,每个对象可以计算出一个哈希码,可以将哈希码分组,
每组分别对应某个存储区域,根据一个对象的哈希码就可以确定该对象应该存储在哪个区域。
如果仅使用 equals()方法保证对象唯一性。每增加一个元素就检查一次,那么当元素很多时,就相当繁琐了。
也就是说,如果集合中现在已经有10000个元素,那么第10001个元素加入集合时,它就要调用10000次equals方法。这显然会大大降低效率。
在哈希表结构的集合中;在添加元素时先调用这个元素的hashCode方法;能够通过哈希码快速定位对象的物理位置;
如果这个位置上没有元素,它就可以直接存储在这个位置上;如果这个位置上已经有元素了,那么就使用equals("DNA")来确认是否为同一个对象
相同的话就不存了,不相同就散列其它的地址。所以这里存在一个冲突解决的问题。
这样一来实际调用equals方法的次数就大大降低了,几乎只需要一两次;执行效率有着明显区别
"注意事项"
(1)在定义集合是往往会自定义覆盖hashCode和equals方法,需要遵守equals的特性规则
equals与hashCode的定义必须一致,两个对象equals为true,就必须有相同的hashCode;反之则不成立"BB&Aa"
例如:如果定义的equals比较的是雇员ID,那么hashCode就需要散列ID,而不是雇员的姓名或住址
用不到哈希表可以不复写,除非你确认类的对象不会放入 HashSet,Hashtable,HashMap.等哈希表集合中。
即使暂时用不到哈希表,为其提供一个与equals一致的hashCode方法也没什么坏处,万一以后用到了呢?
所以,在定义元素类时,为了避免不必要的麻烦,复写equals方法时通常有必要复写hashCode方法,以保证判定结果的一致性。
而在SUN官方的文档中,直接规定"如果重定义equals方法,就必须冲定义hashCode方法,以便用户可以将对象插入到散列(哈希)表中"
(2)当一个对象被存储进HashSet集合中以后,就不能修改这个对象中的那些参与计算哈希值的字段了,
否则,对象修改后的哈希值与最初存储进HashSet集合中时的哈希值就不同了,在这种情况下,
即使在cantains方法使用该对象的当前引用作为的参数去HashSet集合中检索对象,也将返回找不到对象的结果。
这也会导致从HashSet集合中单独删除当前对象,从而造成"内存泄露"。
内存泄露的定义:分配了内存而没有释放,逐渐耗尽内存资源,导致系统崩溃。
现象:如(2)中所述的一种情况,对象一直占用内存空间,无法被垃圾回收机制回收。
IO流操作中如果读写完后不关闭流资源,久而久之也会导致内存泄露
附:
既然说到equals,就片面地提一下 ArrayList 集合为什么增删比较慢
ArrayList 使用了数组结构,使用角标操作使其具备了容器类中最快的查询速度
在添加元素时,需要扩展底层数组的长度所以比较慢(这里简单略过),重点说一下remove操作
查看JDK源码可以发现:
ArrayList 在删除元素时remove方法首先间接调用到了contains方法确认集合中是否含有这个元素,
contains方法使用indexOf()方法的返回值是否>=0来确认是否包含此元素,indexOf方法的原理就是:
使用for循环从0角标依次遍历集合中的元素,使用equals比较每个元素,直到为true时返回此元素的角标
方法调用次序为: remove()--(间接调用)——>contains()——>indexOf()--(for 循环遍历)——>equals()
这就意味着:有10000个元素的 ArrayList 集合在删除元素时,如果恰好要删除的元素位于最后一个角标上
就需要调用10000次equals方法来确认这个元素的位置来进行删除操作!
以上转自http://www.pythontip.com/bigdata/post/4879
在集合框架中 HashSet Hashtable HashMap 都使用了哈希表的形式来存储数据;保证数据唯一的方法;hashCode() & equals();
关于hashCode:
初学者可以粗略的将 hashCode 的值理解为内存地址值,但这不是绝对物理地址,它是经过哈希算法转成的 int 值;
哈希码并不是完全唯一的,它是一种算法,尽量使不同对象拥有不同的哈希码,作为身份的标识
hashCode()的几种算法
1)Object类的hashCode.返回对象的内存地址经过处理后的结构,由于每个对象的内存地址都不一样,所以哈希码也不一样。
2)String类的hashCode.根据String类包含的字符串的内容,根据一种特殊算法返回哈希码,只要字符串所在的堆空间相同,返回的哈希码也相同。
3)Integer类,返回的哈希码就是Integer对象里所包含的那个整数的数值,
例如Integer i1=new Integer(100),i1.hashCode的值就是100 。由此可见,2个一样大小的Integer对象,返回的哈希码也一样。
Object 的哈希码是唯一的,而当对象所对应的类重写了hashCode()方法时,就不一定了。即使两个对象equals为false,也有可能产生相同的哈希码。
例如,字符串"BB"和"Aa"的euqals方法比较结果肯定不相等,但它们的hashCode方法返回值却相等。(都是2112)
但可以确定的是:如果a.equals(b)为 true,a和b必须有相同的哈希码。(规定)
除非你刻意修改参与hashCode计算的字段,如后文注意事项(2)中所述,会导致内存泄露。(将这种行为视为失误或恶意行为)
哈希码的作用:
"哈希码就是对象的身份证" "equals比较相当于匹配对象的DNA" 例如:确定一个人的身份,查身份证号显然要比对比DNA简单得多
hashCode能够"提高哈希表集合的性能"-->快速地定位对象
hashCode算法提高查找的效率,这种方式将集合分成若干个存储区域,每个对象可以计算出一个哈希码,可以将哈希码分组,
每组分别对应某个存储区域,根据一个对象的哈希码就可以确定该对象应该存储在哪个区域。
如果仅使用 equals()方法保证对象唯一性。每增加一个元素就检查一次,那么当元素很多时,就相当繁琐了。
也就是说,如果集合中现在已经有10000个元素,那么第10001个元素加入集合时,它就要调用10000次equals方法。这显然会大大降低效率。
在哈希表结构的集合中;在添加元素时先调用这个元素的hashCode方法;能够通过哈希码快速定位对象的物理位置;
如果这个位置上没有元素,它就可以直接存储在这个位置上;如果这个位置上已经有元素了,那么就使用equals("DNA")来确认是否为同一个对象
相同的话就不存了,不相同就散列其它的地址。所以这里存在一个冲突解决的问题。
这样一来实际调用equals方法的次数就大大降低了,几乎只需要一两次;执行效率有着明显区别
"注意事项"
(1)在定义集合是往往会自定义覆盖hashCode和equals方法,需要遵守equals的特性规则
equals与hashCode的定义必须一致,两个对象equals为true,就必须有相同的hashCode;反之则不成立"BB&Aa"
例如:如果定义的equals比较的是雇员ID,那么hashCode就需要散列ID,而不是雇员的姓名或住址
用不到哈希表可以不复写,除非你确认类的对象不会放入 HashSet,Hashtable,HashMap.等哈希表集合中。
即使暂时用不到哈希表,为其提供一个与equals一致的hashCode方法也没什么坏处,万一以后用到了呢?
所以,在定义元素类时,为了避免不必要的麻烦,复写equals方法时通常有必要复写hashCode方法,以保证判定结果的一致性。
而在SUN官方的文档中,直接规定"如果重定义equals方法,就必须冲定义hashCode方法,以便用户可以将对象插入到散列(哈希)表中"
(2)当一个对象被存储进HashSet集合中以后,就不能修改这个对象中的那些参与计算哈希值的字段了,
否则,对象修改后的哈希值与最初存储进HashSet集合中时的哈希值就不同了,在这种情况下,
即使在cantains方法使用该对象的当前引用作为的参数去HashSet集合中检索对象,也将返回找不到对象的结果。
这也会导致从HashSet集合中单独删除当前对象,从而造成"内存泄露"。
内存泄露的定义:分配了内存而没有释放,逐渐耗尽内存资源,导致系统崩溃。
现象:如(2)中所述的一种情况,对象一直占用内存空间,无法被垃圾回收机制回收。
IO流操作中如果读写完后不关闭流资源,久而久之也会导致内存泄露
附:
既然说到equals,就片面地提一下 ArrayList 集合为什么增删比较慢
ArrayList 使用了数组结构,使用角标操作使其具备了容器类中最快的查询速度
在添加元素时,需要扩展底层数组的长度所以比较慢(这里简单略过),重点说一下remove操作
查看JDK源码可以发现:
ArrayList 在删除元素时remove方法首先间接调用到了contains方法确认集合中是否含有这个元素,
contains方法使用indexOf()方法的返回值是否>=0来确认是否包含此元素,indexOf方法的原理就是:
使用for循环从0角标依次遍历集合中的元素,使用equals比较每个元素,直到为true时返回此元素的角标
方法调用次序为: remove()--(间接调用)——>contains()——>indexOf()--(for 循环遍历)——>equals()
这就意味着:有10000个元素的 ArrayList 集合在删除元素时,如果恰好要删除的元素位于最后一个角标上
就需要调用10000次equals方法来确认这个元素的位置来进行删除操作!
以上转自http://www.pythontip.com/bigdata/post/4879
发表评论
文章已被作者锁定,不允许评论。
-
ReentrantLock与Condition
2017-03-17 14:25 526多线程和并发性并不是什么新内容,但是 Java 语言设计中的创 ... -
java linux监控
2017-03-13 17:49 483http://agapple.iteye.com/blog/1 ... -
transient和volatile两个关键字
2017-02-16 09:47 572transient和volatile两个关 ... -
java 锁机制
2016-12-09 13:43 465一段synchronized的代码被 ... -
java 正则表达式
2016-12-02 10:28 516众所周知,在程序开发中,难免会遇到需要匹配、查找、替换、判断字 ... -
java ClassNotFoundException和NoClassDefFoundException的差别
2016-08-17 19:47 907首先从名字上可以看出一类是异常,一类属于错误。异常可以通过异常 ... -
ThreadLocal
2016-07-19 11:10 327ThreadLocal是什么 Thre ... -
java CAS
2016-07-10 14:55 333cas 乐观锁每次不锁定整个线程,在操作之前进行判断。悲观锁独 ... -
concurrenthashmap
2016-07-10 11:11 422hash table虽然性能上不如 ... -
java 线程池的使用
2016-07-10 09:52 3721. 引言 合理利用线程池能够带来三个好处。第一:降低资源消 ... -
java.util.concurrent
2016-07-03 16:24 409我们都知道,在JDK1.5之 ... -
JVM 配置 以及垃圾收集器的选择
2016-04-15 12:36 728JVM监控的关键指标说明: a) FGC的环比增加次数。Zab ... -
jvm实时监控工具
2016-04-09 09:35 461 -
哈希 、一致性哈希、余数式哈希
2016-04-07 16:10 861什么是Hash Hash,一 ... -
jvm dump 相关
2016-03-22 17:22 681http://www.cnblogs.com/edwardla ... -
深入剖析volatile关键字
2016-03-21 16:02 534深入剖析volatile关键字 ... -
java线程安全问题之静态变量、实例变量、局部变量
2016-03-08 12:52 571java多线程编程中,存在很多线程安全问题,至于什么是线程安全 ... -
有状态的bean和无状态的bean的区别
2016-03-08 11:23 1493有状态会话bean :每个用户有自己特有的一个实例,在用户的生 ... -
Java nio详解
2016-01-20 16:30 551http://www.ibm.com/developerwor ... -
java 不定长数组
2015-11-24 15:00 768在调用某个方法时,若是方法的参数个数事先无法确定该如何处理 ...
相关推荐
"retry.zip"中的开源项目"equals-hashcode-processor-1.0.0"为我们提供了一个优雅的解决方案,通过这个库,我们可以轻松地为Scala Futures实现自动重试逻辑。 首先,我们需要理解Scala Futures的基础。Futures是...
在Java编程语言中,`equals()`方法和`hashCode()`方法是两个非常重要的概念,它们主要用于对象的比较和哈希表的高效运作。本解析将深入探讨这两个方法的用途、实现原理以及它们之间的关联。 首先,`equals()`方法是...
深入理解equals和hashCode方法 equals和hashCode方法是Java中Object类提供的两个重要方法,对以后的学习有很大的帮助。本文将深入剖析这两个方法,帮助读者更好地理解和使用它们。 equals方法 equals方法是用于...
在Java编程语言中,`equals()` 和 `hashCode()` 方法是对象的基本组成部分,它们在很多场景下都发挥着至关重要的作用。这两个方法与对象的相等性比较和哈希表(如HashMap、HashSet)的运作紧密相关。这篇博客将深入...
在Java编程语言中,`hashCode()`和`equals()`方法是非常重要的概念,它们不仅对于深入理解Java内存管理至关重要,也是实现自定义类的关键部分之一。本文将详细介绍这两个方法的工作原理、使用场景以及它们之间的关系...
深入解析Java对象的equals()和hashCode()的使用 在Java语言中,equals()和hashCode()两个函数的使用是紧密配合的,你要是自己设计其中一个,就要设计另外一个。在多数情况下,这两个函数是不用考虑的,直接使用它们...
在深入探讨`hashCode`方法之前,我们需要了解Java集合框架的基本概念。Java集合框架主要包括两大类集合:`List`和`Set`。 - **List**:这是一个有序集合,允许元素重复。 - **Set**:这是一个不允许元素重复的无序...
### 深入理解 HashCode 方法 #### 一、HashCode 的基本概念与作用 在 Java 编程语言中,`HashCode` 是一个非常重要且基础的概念。简单来说,`HashCode` 是一个整数值,用于快速定位对象的位置。在 Java 中,每一个...
通过对 hashCode 和 equals 方法的深入分析,我们可以更好地理解 Java 集合的实现原理和哈希表的工作机制。 一、hashCode 方法简介 hashCode 方法是 Java 中 Object 类的一个方法,用于返回对象的哈希码值。这个...
### set接口中hashCode和equals方法详解 #### 一、引言 在Java编程语言中,`Set`接口作为集合框架的重要组成部分,在实现无重复元素的数据结构方面扮演着关键角色。为了确保元素的唯一性,`Set`接口依赖于对象的`...
`equals()` 方法用于判断两个对象是否相等,而 `hashCode()` 方法则与对象的哈希值有关,这对于理解和使用Java中的集合框架至关重要。 `equals()` 方法是Object类的一个成员方法,它的默认行为是基于引用比较,即...
"java中的哈希算法和hashcode深入讲解" 哈希算法是计算机领域中非常重要的一种技术,它具有非常广泛的应用,例如快速查找和加密。哈希算法可以将任意长度的二进制值映射为较短的、固定长度的二进制值,这个二进制值...
二、`hashCode()`与`equals()`的关系 `hashCode()`和`equals()`方法密切相关。当两个对象通过`equals()`方法判断相等时,它们的`hashCode()`值也必须相等。反之,如果两个对象的`equals()`方法返回`false`,那么...
现在,让我们深入探讨为什么重写 `equals()` 时要重写 `hashCode()`: 1. **一致性**:一旦对象被创建并赋予了特定的值,其 `equals()` 和 `hashCode()` 方法的结果就应该保持不变,即使在程序的不同执行期间也是...
### hashCode与equals方法详解 在Java编程语言中,`hashCode`和`equals`方法是非常重要的概念,它们在处理对象的比较、存储以及检索时扮演着关键角色。本文将深入探讨这两个方法之间的区别,并通过具体例子来说明...
同时,`equals`方法和`hashCode`方法应当一起重写,以确保对象相等时其哈希码也相等,这是HashMap等数据结构正确工作的前提。 总的来说,深入理解并正确实现`equals`方法是Java编程中的基础但关键的技能。这涉及到...
在Java编程语言中,`hashCode()`与`equals()`方法是非常重要的概念,它们不仅对于深入理解Java内存管理至关重要,也是实现自定义类的关键部分之一。本文将详细介绍这两个方法的工作原理、使用场景以及在Java集合框架...
Object类是所有Java类的根类,它定义了一些常用的方法,例如equals()、hashCode()、toString()等。本案例代码将详细展示Object类的使用方法,并提供一些实际场景下的案例,以帮助开发者更好地理解和运用这些方法。 ...
对于自定义类,尤其是使用了数据传输对象(DTO)的情况下,未正确重写equals和hashCode可能导致内存泄漏。当一个对象被放入哈希集合(如HashSet或HashMap)时,其equals和hashCode方法用于确定对象的身份。如果这两...