黑马程序员技术交流社区

标题: HashSet中的哈希值和地址的问题 [打印本页]

作者: 黑马张旭明    时间: 2012-8-18 21:05
标题: HashSet中的哈希值和地址的问题
每个对象都有地址值,输出为:类名@哈希值。对象都有个hashCode()方法,hashCode返回和地址值里哈希值一样的哈希值,今天看视频讲到HashSet判断是否为同一个对象先判断哈希值然后再equals(),我不明白如果哈希值一样的话地址应该一样啊,同一个地址的话内存里存的东西怎么会不同,求解释
作者: 张忠豹    时间: 2012-8-18 21:33
package day17;

public class TestYunSuanFu {
        public static void main(String args[]){
                 System.out.println("Aa".hashCode());
         System.out.println("BB".hashCode());

        }
}

作者: 张忠豹    时间: 2012-8-18 21:44
本帖最后由 张忠豹 于 2012-8-18 21:46 编辑

public class TestYunSuanFu {
        public static void main(String args[]){
//输出这条语句,你会发现,他们的hascode是一样的,但是,它们的值完全不一样
                 System.out.println("Aa".hashCode());
                System.out.println("BB".hashCode());

        }
}
public class TestYunSuanFu {
        public static void main(String args[]){
//输出这条语句,你会发现,他们的hascode是一样的,但是,它们的值完全不一样
                 System.out.println("Aa".hashCode());
                System.out.println("BB".hashCode());

        }
}
两个对象相等,hashCode一定相等,equals不一定相等,反之不成立
毕老师教程视频中已经说了,如果相等就在原地址的位置顺延一个位置保存,这个位置据个人估计应该是链式的,因为当你看到张老师的基础加强视频以后你会明白,哈希表存储的底层数据结构是在内存中根据哈希表的值分成不同的段,这个是线式的,当有一个新元素进来时,会根据它的哈希值在内存中取哈希表分区的模,然后根据结果区域比较区域内的各个元素的哈希值,如果相等,就用毕老师在课上说的方法,在内存中顺延一个位置保存,但是这两个位置的哈希值都是一样的~~
作者: 杜佳瑞    时间: 2012-8-18 21:54
       Object里的hashCode()方法针对不同的对象返回不同的哈希值,这个哈希值是通过将该对象的内部地址转换成一个整数。一般情况下我们说的不同的对象都是new出来的,即使内容一样,系统也会认为是不同对象分配不同的地址,也就有了哈希值的不同。但是往往我们把内容一样就视作通一个对象。那就只能复写Object里的hashCode()方法了,这个方法一般按照类中成员计算哈希值。
      只有HashSet集合才会调用hashCode()方法,因为HashSet集合的底层基于哈希表,哈希表根据哈希值分配了很多的区域,因为hashCode()经过复写算出的哈希值是通过对象内容计算出来的,所以只要内容一样哈希值肯定一样,这样就会被分配到哈希表中同一个区域,进一步通过equals()方法判断,如果这个方法再返回true说明对象是同一个对象。
       楼主提到哈希值一样,但是存入的东西会不同,这是有可能的。因为哈希值是通过对象里的成员算出来的,肯定会有一定的几率由不同内容算出同一个值的,这样就会进一步通过equals()比较。如果不同的话说明不是同一个对象,但是对象也会存入同一个哈希地址上(视频中这块好像老师讲的挺细的)
作者: 杨彪    时间: 2012-8-18 22:26
HashSet就是采用哈希算法存取对象的集合,它内部采用对某个数字n进行取余的方式对哈希码进行分组和划分对象的存储区域。Object类中定义了一个hashCode()方法来返回每个Java对象的哈希码,当从HashSet集合中查找某个对象时,Java系统首先调用对象的hashCode()方法获得该对象的哈希码,然后根据哈希码找到相应的存储区域,最后取出该存储区域内的每个元素与该对象进行equals方法比较,这样不用遍历集合中的素有元素就可以的到结论。可见,HashSet集合具有很好的对象检索性能,但是,HashSet集合存储对象的效率相对要低些,因为向HashSet集合中添加一个对象时,要先计算出对象的哈希码和根据这个哈希码确定对象在集合中的存放位置。
只有类的实例对象要被采用哈希算法进行存储和检索时,这个类才需要按要求覆盖hashCode方法。即使程序可能暂时不会用到当前类的hashCode方法,但是为它提供了一个hashCode方法也不会有什么不好,没准以后什么时候又用到这个方法了,所以,通常要求hashCode方法和equals方法一并被同时覆盖。
通常来说,一个类的两个实例对象用equals()方法比较的结果相等时,它们的哈希码也必须相等,但反之则不成立,即equals方法比较结果不相等的对象可以有相等的哈希码,或者说哈希码相同的两个对象的equals方法比较的结果可以不相等。
当一个对象被存储进HashSet集合中以后,就不能修改这个对象的那些参与计算哈希值的字段了,否则,对象修改后的哈希值与最初存储进HashSet集合中的哈希值就不同了,在这种情况下,即使在contains方法使用该对象的当前引用作为的参数去HashSet集合中检索对象,也将返回找不到对象的结果,这也导致无法从HashSet集合中单独删除当前对象,从而造成内存泄漏。
作者: 胡文凡    时间: 2012-8-18 22:43
首先hascode和equals方法可以自己定义的。所以不会有什么哈希值相同内存地址就相同的说法。
Java对于eqauls方法和hashCode方法是这样规定的:
1、如果两个对象相同,那么它们的hashCode值一定要相同;2、如果两个对象的hashCode相同,它们并不一定相同     上面说的对象相同指的是用eqauls方法比较。  
你当然可以不按要求去做了,但你会发现,相同的对象可以出现在Set集合中。同时,增加新元素的效率会大大下降。





欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2