`
longxiaoyan
  • 浏览: 77362 次
  • 性别: Icon_minigender_1
  • 来自: 桂-京
社区版块
存档分类
最新评论

理解 hashcode

阅读更多
hashcode的作用就是为了快速查找集合中是否存在重复元素。它是配合euqals方法使用的。

先简要介绍equals方法:在object中此方法比较两个对象的地址是不是相等。api中的一些类重写了此方法,如String重写了此方法(但StringBuffer没有重写此方法),比较的是两个字符串的内容是不是相等。因此我们在定义一个对象的时候也可以重写equals方法,按照我们的原则来定义。

再看一个问题:
为什么重写了equals方法需要重写hashcode方法?
答:为了更快判断集合中是否已存在某对象。对于链表和数组,如果我们要查找某个元素是否已经存在,我们需要遍历数组和链表,直到找到这个元素位置,这样很耗时间(事实上,链表和数组在加入一个元素时也没有判断它是否存在,因此可以有重复)。如果我们使用哈希表,我们就可以根据这个元素的hashcode方法和equals方法快速判断集合中是否已存在某对象。下面对此进行描述:

哈希表由哈希表元地址和哈希表元组成,是一个链表的数组。在java中,哈希码就是根据对象的hashcode方法产生的哈希码(hashcode一般是根据对象的成员变量生成哈希码)。一般而言,不同的对象有不同的hashcode,但也可能不同的对象拥有同一个哈希码。但是哈希表元地址是如何与哈希码匹配的呢?举个例子吧:
假设现在有16个哈希表元,那么哈希表元地址则为1到16,然后现在有个对象的哈希码为329,329%16=9,则这个对象就存储在哈希表元地址为9的哈希表元上。假设现在又有一个对象的哈希码为25,25%16=9,好的,由于哈希地址为9的哈希表元上已经有元素了,这时新存进来的对象就要遍历这个哈希表元(不是全部元素),通过equals方法判断这个哈希表元上是否已经存在相同对象,如果不存在,就继续存储在哈希表元的后面。
总结如下:每要添加一个对象,都是先获取它的hashcode值,然后一次就匹配了哈希表元地址,如果哈希表元上还没有存储对象,就直接存储,如果已经有了就遍历哈希表元(通过equals方法判断是否有相同对象存在),如果不存在相同对象就存储在哈希表元后面。


现在我们来看看HashSet的add方法,当add一个对象时,会根据这个对象生成的hashcode值快速到链表数组中匹配对应的哈希表元,如果哈希表元为空的,就可以把对象插入哈希表元中,然后返回true。如果哈希表元中已经有元素,这时就要遍历这个哈希表元(记住,只是遍历其中一个哈希表元,而不是集合中的所有元素,可能就一两个元素),通过equals方法来判断是否已经有相同的对象存在,如果有则返回false,如果没有则找空间存贮对象并链接到这个哈希表元的后面。
看完这里应该就明白了为什么重写equals方法还要重写hashcode方法,就是为了快速查找集合中是否存在重复元素。
记住一个原则:如果a.equals(b)为true时,a和b必须拥有相同的hashcode。

举个例子说明:
public class Person {
	private String name;
	private int age;

	@Override
	public int hashCode() {
		return age+name.hashCode();
	}
	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Test3 other = (Test3) obj;
		if (age != other.age)
			return false;
		if (name == null) {
			if (other.name != null)
				return false;
		} else if (!name.equals(other.name))
			return false;
		return true;
	} 
}

假设现在new出两个Person对象:
	Person p1 = new Person();
	Person p2 = new Person();

我们上述实现的equals方法和hashcode方法必须满足下面条件:
1. p1.equals(p2)为true时,p1和p2必须拥有相同的哈希码。
2. p1和p2拥有相同的哈希码时,p1.equals(p2)不一定为true。

对于第二点我们可以设想一下:
p1.age=24; p1.name.hashcode=109;
p2.age=27;p2.name.hashcode=106;

因此p1和p2的hashcode相同,但p1.equals(p2)为false。





hashcode() 方法,在object 类中定义如下:
public native int hashCode(); <完>
说 明是一个本地方法,它的实现是根据本地机器相关的 。当然我们可以在自己写的类中覆盖hashcode() 方法,比如String 、Integer 、 Double 。。。。等等这些类都是覆盖了hashcode() 方法的。例如在String 类中定义的hashcode() 方法如下:
public int hashCode() {
int h = hash;
if (h == 0) {
int off = offset;
char val[] = value;
int len = count;

for (int i = 0; i < len; i++) {
h = 31*h + val[off++];
}
hash = h;
}
return h;
}
解释一下这个程序(String 的API 中写到):
s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]
使用 int 算法,这里 s[i] 是字符串的第 i 个字符,n 是字符串的长度,^ 表示求幂。(空字符串的哈希码为 0 。)
首先,想要明白hashCode 的作用,你必须要先知道Java 中的集合 。  
总的来说,Java 中的集合(Collection )有两类,一类是List ,再有一类是Set 。
你知道它们的区别吗?前者集合内的元素是有序的,元素可以重复;后者元素无序,但元素不可重复。
那么这里就有一个比较严重的问题了:要想保证元素不重复,可两个元素是否重复应该依据什么来判断呢?
这就是Object.equals 方法了 。但是,如果每增加一个元素就检查一次,那么当元素很多时,后添加到集合中的元素比较的次数就非常多了。
也就是说,如果集合中现在已经有1000 个元素,那么第1001 个元素加入集合时,它就要调用1000 次equals 方法。这显然会大大降低效率。   
于是,Java 采用了哈希表的原理。哈希(Hash )实际上是个人名,由于他提出一哈希算法的概念,所以就以他的名字命名了。
哈希算法也称为散列算法,是将数据依特定算法直接指定到一个地址上 。如果详细讲解哈希算法,那需要更多的文章篇幅,我在这里就不介绍了。
初学者可以这样理解,hashCode 方法实际上返回的就是对象存储的物理地址(实际可能并不是)。   
这样一来,当集合要添加新的元素时,先调用这个元素的hashCode 方法,就一下子能定位到它应该放置的物理位置上。
如果这个位置上没有元素,它就可以直接存储在这个位置上,不用再进行任何比较了;如果这个位置上已经有元素了,
就调用它的equals 方法与新元素进行比较,相同的话就不存了,不相同就散列其它的地址。
所以这里存在一个冲突解决的问题。这样一来实际调用equals 方法的次数就大大降低了,几乎只需要一两次。  
所以,Java 对于eqauls 方法和hashCode 方法是这样规定的:
1 、如果两个对象相同,那么它们的hashCode 值一定要相同;2 、如果两个对象的hashCode 相同,它们并不一定相同     上面说的对象相同指的是用eqauls 方法比较 。  
你当然可以不按要求去做了,但你会发现,相同的对象可以出现在Set 集合中。同时,增加新元素的效率会大大下降。
  • 大小: 21.7 KB
0
1
分享到:
评论
1 楼 hello冷风 2010-04-14  
楼主写不错,其实再去看看算法书上关于哈希表处理哈希值冲突可以发现这只是其中一种实现方式

相关推荐

    深入 HashCode 方法~

    ### 深入理解 HashCode 方法 #### 一、HashCode 的基本概念与作用 在 Java 编程语言中,`HashCode` 是一个非常重要且基础的概念。简单来说,`HashCode` 是一个整数值,用于快速定位对象的位置。在 Java 中,每一个...

    深入HashCode方法

    《深入理解HashCode方法》 HashCode方法在Java编程中扮演着至关重要的角色,尤其是在涉及对象存储和查找效率的数据结构,如HashMap和Hashtable中。一个对象的HashCode是一个简单的哈希算法实现,尽管它相对复杂的...

    深入理解Java中HashCode方法

    深入理解Java中HashCode方法 Java中的hashCode方法是每个类都需要实现的重要方法之一,它的主要作用是将对象的数据转换为一个32位的整数,用于标识对象的唯一性。在Java的所有类中,Object类是最顶层的父类,它定义...

    hashCode的理解

    java中hashCode()的理解

    OCJP认证-3期(PX017) PX122010101018_OCJP考试大纲 -.doc

    深入理解hashCode()和equals()方法的重要性,以及Comparable接口和Comparator接口在排序中的作用。 输入输出流是Java处理数据传输的关键,考试会涉及文件类,如File,以及各种输入/输出流,包括FileInputStream、...

    重写equals和hashcode方法_equals_重写equals和hashcode方法_

    总的来说,理解并正确地重写 `equals()` 和 `hashCode()` 方法是Java编程中的基础技能,它有助于确保对象的比较和集合操作的正确性。在开发过程中,要时刻注意这两个方法的正确实现,以提高代码质量和可维护性。

    hashcode的作用

    ### HashCode的作用详解 #### 一、HashCode的基本概念 在Java中,`hashCode()` 方法是 `Object` 类的一个重要成员方法,它返回一个整数,这个整数...开发者应当充分理解其工作原理,并结合实际情况进行适当的优化。

    深入HashCode

    《深入HashCode》 在计算机科学领域,特别是在Java和许多其他面向...理解和正确实现`hashCode()`是每个程序员必备的技能之一。通过合理设计和优化`hashCode()`方法,我们可以提高程序的性能并确保数据结构的正确性。

    hashCode的作用

    为了更好地理解`hashCode`的作用及其在实际开发中的重要性,我们可以从以下几个方面进行深入探讨: #### 1. 基本概念 `hashCode`方法是`java.lang.Object`类中的一个方法,所有Java类都继承自`Object`类,因此每个...

    hashcode-framework:Hashcode PHP框架

    结合【标签】"HTML",我们可以理解Hashcode Framework不仅关注后端逻辑,还关注前端展示。HTML是超文本标记语言,用于构建和设计网页内容。框架可能提供了一些便捷的工具或者模板引擎,使得开发者可以更轻松地创建和...

    HashCode相同equals不同的2位字符集合算法

    总之,理解并正确实现`hashCode()`和`equals()`对于优化Java集合框架的性能和避免逻辑错误至关重要。在处理特定情况,如2位字符集合时,需要特别注意哈希冲突的可能性,并采取适当的策略来减少它们。通过这种方式,...

    java中hashcode()和equals()的详解

    理解这两个方法的工作原理对于编写高效和可靠的代码至关重要。 首先,`equals()`方法是Object类中的一个基础方法,用于比较两个对象是否相等。默认情况下,`equals()`方法会比较对象的内存地址,也就是说,只有当两...

    利用反射绕过编译器和hashcode高级应用

    首先,让我们理解反射的基本概念。在Java中,反射提供了一种方式,使我们能够在运行时动态地获取类的信息(如类名、属性、方法等),并能够调用私有方法、访问私有变量,甚至创建未知类型的对象。这种能力使得程序员...

    Java基础加强_ArrayList_HashSet的比较及Hashcode分析

    在Java编程语言中,ArrayList和HashSet是两种常用的...理解这两个数据结构的特点以及如何利用Hashcode优化性能,对于提高代码效率和可维护性至关重要。学习和掌握这些基础知识,将有助于成为一名更优秀的Java开发者。

    equals,hashcode,toString

    在Java编程语言中,`equals()`, `hashCode()` 和 `toString()` 是三个非常重要的方法,它们主要用于对象的比较、哈希存储以及打印对象信息。这三个方法是Java对象的基础特性,对于理解和开发高质量的Java程序至关...

    Java_重写equals()和hashCode()

    总之,理解并正确重写 `equals()` 和 `hashCode()` 方法对于编写高质量的Java代码至关重要,这直接影响到对象比较的逻辑以及使用哈希表的数据结构的效率。通过遵循上述原则和最佳实践,我们可以确保对象的比较行为...

    java中hashcode()和equals()方法详解

    在Java编程语言中,`hashCode()`和`equals()`方法是非常重要的概念,它们不仅对于深入理解Java内存管理至关重要,也是实现自定义类的关键部分之一。本文将详细介绍这两个方法的工作原理、使用场景以及它们之间的关系...

    hashcode与eqault比较

    综上所述,正确理解和使用`equals`和`hashCode`方法对于编写高质量的Java程序至关重要。通过对这两个方法的合理覆盖,可以有效地提高数据结构(如`HashSet`和`HashMap`)的操作效率,同时也能更好地支持对象之间的...

    java 序列化和重写 hashCode 的原因

    在Java编程语言中,序列化(Serialization)和重写`hashCode`及`equals`方法是两个重要的概念,它们各自有着特定的用途,并且在...在实际开发中,理解并恰当地应用这些概念对于构建高效、健壮的Java应用程序至关重要。

Global site tag (gtag.js) - Google Analytics