A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 周朋飞 中级黑马   /  2012-6-27 10:21  /  2404 人查看  /  5 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

本帖最后由 周朋飞 于 2012-6-28 11:28 编辑

昨天看了毕老师最后的一个视频也就是练习的题目,有一点不是很明白,为什么比较对象不是已经实现了compareTo方法了吗,为什么还要重写hashcode和equals方法,而且两个都得重写 hashcode算法具体怎么用,什么时候用啊

5 个回复

倒序浏览
我们需要判断两个对象是否相等。Java的每个类都继承于Object类。它使用equals()及hashCode()这两个方法来判断两个Object是否相等。


1. equals()
需要满足5点:
1 自省:对于任一非null引用x,x.equals(x)应返回true;
2 反射:对于任一非null引用x及y,仅在y.equals(x)返回true时,x.equals(y)才返回true;
3 传递:对于任一非null引用x、y及z,如果x.equals(y)为true,而且y.equals(z)为true,则x.equals(z)应返回true;
4 稳定:对于任一非null引用x及y,如果用于比较的信息没有改变,无论多少次调用x.equals(y)都会恒定地返回true或false;
5 对于任一非null引用x,x.equals(null)应返回false。

Object的默认实现是只要在两个Object的引用相等时,才会返回true,即return x == y;

如果要覆盖(override)此方法,需要同时覆盖hasCode(),要求是:两个相等的对象必须有相等的hash code。

2. hashCode()
其必须遵循的约定是:
1 如果对象equals, 则hashCode一定相等;
2 如果equals()返回false,这两个对象的hashCode()可能相同。但不等的两个对象返回不同的int值可以提高hashtables的运行效率。

   作为常理,不相等的对象的hasCode()应可能地返回不同的int值。

3. 对象是否相等的规则
1 判断两个对象的hashCode是否相等; 如果不相等,认为两个对象也不相等, 完毕.
2 如果相等, 再调用equals方法.

4. hashCode最大的用处是什么呢?
Java中的集合(Collection)有两类,一类是List,再有一类是Set。
你知道它们的区别吗?前者集合内的元素是有序的,元素可以重复;后者元素无序,但元素不可重复。
那么这里就有一个比较严重的问题了:要想保证元素不重复,可两个元素是否重复应该依据什么来判断呢?
这就是Object.equals方法了。但是,如果每增加一个元素就检查一次,那么当元素很多时,后添加到集合中的元素比较的次数就非常多了。
Java采用了哈希表的原理, 哈希算法也称为散列算法,是将数据依特定算法直接指定到一个地址上. 初学者可以这样理解,hashCode方法实际上返回的就是对象存储的物理地址(实际可能并不是)。
有了hashCode,当集合要添加新的元素时,先调用这个元素的hashCode方法,就一下子能定位到它应该放置的物理位置上。
如果这个位置上没有元素,它就可以直接存储在这个位置上,不用再进行任何比较了;如果这个位置上已经有元素了,
就调用它的equals方法与新元素进行比较,相同的话就不存了,不相同就散列其它的地址。
所以这里存在一个冲突解决的问题。这样一来实际调用equals方法的次数就大大降低了,几乎只需要一两次.

5. 为什么在HIBERNA里要重写hashCode和equals这两个方法?
在hibernate中,经常使用set集合来保存相关对象,而set集合是不允许重复的, so, 道理同4.

点评

警告一次,在百度复制粘贴俺要扣分了  发表于 2012-6-28 15:39
回复 使用道具 举报
hashCode的哈希值不相同当存储自定义对象的时候,如果没有重写hashCode()方法,那么就会调用Object类的hashCode(),得到当前对象的地址,地址不同就不能去重复.
当存储对象的时候,先调用对象的hashCode()方法计算一个哈希值,然后在集合中查找是否有哈希值相同的对象,如果没有哈希值相同的对象,那么直接存入,如果有哈希值相同的对象,调用equals()方法比较,比较结果为true就不存,比较结果为fals则存入,如果希望将属性相同的对象去重复,那么属性相同的对象要返回相同的哈希值.

hashcode是对象在key-value映射集合当中hash函数生成的hash码,可以通过hashcode反算出对象地址,非常适合快速查找。JAVA对象的hashcode是通过对象的地址算出来的整数,不会重复,hashcode方法就是返加这个hashcode的方法,而equals只是比较对象内容是否相等,比如比较对象中所有的属性是否相等。

评分

参与人数 1技术分 +1 收起 理由
刘蕴学 + 1 有一点你说错,hashcode不是唯一的,取值范.

查看全部评分

回复 使用道具 举报
hashcode和equals方法是HashMap集合需要用到的比较方式,HashMap底层的数据结构是哈希表。
compareTo是HashSet集合需要用到的方法,HashSet底层的数据结构是二叉树。

点评

再往下你会发现是map,呵呵  发表于 2012-6-28 19:06

评分

参与人数 1技术分 +1 收起 理由
刘蕴学 + 1 源码还是翻的在深点

查看全部评分

回复 使用道具 举报
引用一下  说的很好  我已经理解了
1)对于一个程序的一次执行过程中,同一个对象的hashCode计算的结果一定相同,但是对于同一个程序的不同执行过程中,不要求其hashCode一定相同。

2)对于两个对象,如果使用equals方法比较,结果为true,那么这两个对象的hashCode值一定相同

3)对于两个对象,如果使用equals方法比较,结果为false,那么这两个对象的hashCode值不要求一定不同(但是如果不同可以提高程序性能)
当我们向HashSet中add对象,它首先调用它的HashCode方法,得到这个HashCode的返回整数值,这个整数值就会映射到set里面的某一个位置。如果这个对象里没有对象存在,就把这个对象直接放发哦set里面;如果这个位置已经有对象存在了,这个时候就用equals方法比较这两个方法,如果比较结果相同,就不进行插入。比如下面问题



Set set = new HashSet();

set.add("zhangsan");

set.add("lisi");

set.add("wangwu");

set.add("zhangsan");

这个最后一个set.add("zhangsan");是无法插入成功的,因为String重写了Object的equlas和HashCode方法,按照String的HashCode方法,相同的字符串的HashCode一定是一样的

下面详细分析最后一个set.add("zhangsan")具体插入过程

1.首先根据"zhangsan"调用HashCode方法,获得一个返回值

2.Set根据这个返回值获得一个位置

3.查找这个位置上是否有对象,结果发现有一个对象。值也是“zhangsan”

4.对两个对象调用equals方法,由于String重写了equals方法,这个方法返回true。

所以最后插入失败。
回复 使用道具 举报
引用一下  说的很好  我已经理解了
1)对于一个程序的一次执行过程中,同一个对象的hashCode计算的结果一定相同,但是对于同一个程序的不同执行过程中,不要求其hashCode一定相同。

2)对于两个对象,如果使用equals方法比较,结果为true,那么这两个对象的hashCode值一定相同

3)对于两个对象,如果使用equals方法比较,结果为false,那么这两个对象的hashCode值不要求一定不同(但是如果不同可以提高程序性能)
当我们向HashSet中add对象,它首先调用它的HashCode方法,得到这个HashCode的返回整数值,这个整数值就会映射到set里面的某一个位置。如果这个对象里没有对象存在,就把这个对象直接放发哦set里面;如果这个位置已经有对象存在了,这个时候就用equals方法比较这两个方法,如果比较结果相同,就不进行插入。比如下面问题



Set set = new HashSet();

set.add("zhangsan");

set.add("lisi");

set.add("wangwu");

set.add("zhangsan");

这个最后一个set.add("zhangsan");是无法插入成功的,因为String重写了Object的equlas和HashCode方法,按照String的HashCode方法,相同的字符串的HashCode一定是一样的

下面详细分析最后一个set.add("zhangsan")具体插入过程

1.首先根据"zhangsan"调用HashCode方法,获得一个返回值

2.Set根据这个返回值获得一个位置

3.查找这个位置上是否有对象,结果发现有一个对象。值也是“zhangsan”

4.对两个对象调用equals方法,由于String重写了equals方法,这个方法返回true。

所以最后插入失败。
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马