`
longxiaoyan
  • 浏览: 75951 次
  • 性别: 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  
楼主写不错,其实再去看看算法书上关于哈希表处理哈希值冲突可以发现这只是其中一种实现方式

相关推荐

    深入理解Java中HashCode方法

    主要介绍了深入理解Java中HashCode方法,具有一定借鉴价值,需要的朋友可以参考下

    深入理解equals和hashCode方法

    在Java中,equals和hashCode方法是Object中提供的两个方法,这两个方法对以后的学习有很大的帮助,本文就深度来去讲解这两个方法。下面小编带大家来一起学习吧

    hashCode的理解

    java中hashCode()的理解

    关于Java中HashCode方法的深入理解

    主要给大家介绍了关于Java中HashCode方法的相关资料,文中通过示例代码介绍的非常详细,对大家学习或者使用Java具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧

    hashCode内存溢出和内存泄漏的问题解决.docx

    所以程序中的内存泄漏我的理解更多是:由于程序的编写错误暴漏出一些 开口 ,导致一些对象 进入 这写开口,最终 导致相关问题 ,进一步说白了,程序有漏洞,不当的调用就会出问题 内存泄漏说明的是这样一种...

    Java中hashCode和equals方法的正确使用

    在这篇文章中,我将告诉大家我对hashCode和equals方法的理解。我将讨论他们的默认实现,以及如何正确的重写他们。我也将使用Apache Commons提供的工具包做一个实现。  hashCode()和equals()定义在Object类中,这...

    Java hashCode() 方法详细解读

    Java.lang.Object 有一个hashCode()和一个equals()方法,这两个方法在软件设计中扮演着举足轻重的角色,本文对hashCode()方法深入理解,希望能帮助大家

    Java的Object类讲解案例代码 equals()、hashCode()、finalize()、clone()、wait()

    内容概要 这个源码资源是关于Java中的Object类的讲解案例代码。Object类是所有Java类的根类...理解equals()、hashCode()、toString()等常用方法的用途。 学会正确重写这些方法,以满足特定需求。应用实例代码中提供的场

    Java面试题.docx

    1、java中==和equals和hashCode的区别 2、int与integer的区别 3、String、StringBuffer、StringBuilder区别 4、什么是内部类?内部类的作用 5、进程和线程的区别 6、final,finally,finalize的区别 7、...

    8张图理解Java

     2、equals()方法、hashCode()方法的区别  HashCode被设计用来提高性能。equals()方法与hashCode()方法的区别在于:  如果两个对象相等(equal),那么他们一定有相同的哈希值。  如果两个对象的哈希值相同,...

    涵盖了90%以上的面试题

    为什么重写equals还要重写hashCode? 介绍一下volatile jdk1.5新特性 jdk1.7新特性 jdk1.8新特性 java语言有哪些优点? 同一个.java文件中是否可以有多个main方法 一个".java"源文件中是否可以包括多个类(不是内部类...

    Java实例高难度面试题及解析 - 展现你的编程实力!

    此外,我们还探讨了对象的哈希码、重写equals()和hashCode()方法的技巧,以及对象的序列化和反序列化。 通过研究和解答这些高难度问题,您将提升自己的编程水平,展现出对Java实例概念和相关技术的深入理解。无论您...

    AIC的Java课程1-6章

    第9章 常用类 4课时  理解Object类及其常用方法equals,hashCode和finalize等。  能够使用String,StringBuffer,StringBuilder类创建字符串对象和使用其方法,分辨不同类之间的区别。 ...

    观看韩顺平学习整理java的笔记到异常

    帮助大家复习java基础知识其中有 hashCode 2 toString 2 finalize 2 用已学知识做出简单的房屋出租系统 3 类方法使用注意事项和细节讨论 4 main()方法 4 代码块 4 代码块使用注意事项和细节 5 单例模式 6 final...

    安卓java读取网页源码-AndroidInterview:Android面试常见问题

    安卓java读取网页源码 一、java 熟练掌握java是很关键的,大公司不仅仅要求你会使用几个api,更多的是要你熟悉源码实现原理,甚至要你知道...谈谈对java多态的理解 所谓多态就是指程序中定义的引用变量所指向的具体类型

    sesvc.exe 阿萨德

    一文让你彻底理解 Java HashMap 和 ConcurrentHashMap 2018-07-25 分类:JAVA开发、编程开发、首页精华0人评论 来源:crossoverjie.top 分享到:更多0 前言 Map 这样的 Key Value 在软件开发中是非常经典的结构,常...

    安卓java读取网页源码-questions:自问自答

    hashCode 有什么区别 说说你对 final 修饰符的理解 说说你对泛型的理解 泛型中 extends 和 super 的区别 描述下 Java 中的异常处理机制 什么是 HashMap,描述下其实现原理 HashMap、Hashtable 和 HashSet 这三者有...

    Object类和toString()方法.pptx

    认识toString()方法并理解其作用 能在一些类里正确重写toString()方法 理解toString()方法的执行机制;public class MyClass { } ;4;System.out.print(对象); //自动调用toString()方法 等价于 System.out.print...

    Java中HashMap和TreeMap的区别深入理解

     HashMap通过hashcode对其内容进行快速查找,而 TreeMap中所有的元素都保持着某种固定的顺序,如果你需要得到一个有序的结果你应该使用TreeMap(HashMap中元素的排列顺序是不固定的)。  HashMap 非线程安全 ...

    Java Object 类高难度进阶版面试题集锦解析Java Object类高难度面试题及答案解析

    提供了20道高难度的Java Object类面试题及详细答案解析,涵盖了equals()、hashCode()、toString()、clone()、finalize()等方法的重写和应用,以及对象的比较、克隆、标识哈希码等概念。适合准备Java面试的开发者深入...

Global site tag (gtag.js) - Google Analytics