关于HashSet的存储原理

关于HashSet的存储原理

1.HashSet是Java容器中的一种具体实现,可以用来存储无序且不重复的元素:

​ 1.无序性:不等于随机性。存储的数据在底层素组中并非按照素组索引的顺序添加,而是根据数据的哈希值来决定数据存储的位置。

​ 2.不可重复性:保证添加的元素以equals()判断是不能返回true。即相同的元素只能添加一个。

2.HashSet中元素的添加过程:

​ 我们向HashSet中添加元素a,首先调用元素a所在类的hashcode( )方法,来计算出元素a的哈希值,然后通过此哈希值来找到HashSet底层数组中应该存放的位置(即数组的索引位置),再此会出现两种情况,第一种情况是该位置上无已存数据,因此直接存放即可成功;第二种情况便是该位置上已存放数据,而我们在开头强调过HashSet只能存放不重复的数据,因此我们需要将待插入元素与已插入元素进行比对,具体如下流程:

​ 我们在此定义待插入元素为a,已插入元素为b,首先对比a与b的哈希值进行比对,若a与b的哈希值不相同,则a元素顺利插入;若a与b的哈希值相同,则需要进一步的调用a所在类的equals( )方法与b进行比较,若返回false则可添加成功,若返回true则表明a与b元素为重复元素,不可重复添加。而对于这两种成功插入的情况,本身指定索引已经存在数据,那么是如何插入成功的呢?答案是链表:即元素a与元素b以链表的方式进行存储。(不同版本的jdk链表的实现方式有所不同jdk7是将a放入底层数组中,jdk8是将a与数组中的元素建立连接)

3.对存储对象所在类的要求:

​ 在了解了HashSet元素添加的原理后,我们可以明确存储对象的所在类必须满足的条件:重写hashcode( )与equals( )方法。

4.案例:

@Test
    public void test1(){
        HashSet hashSet = new HashSet();
        Person p1 = new Person(1001, "AA");
        Person p2 = new Person(1002, "BB");
        hashSet.add(p1);
        hashSet.add(p2);
        System.out.println("查看初始化后的hashset:");
        System.out.println(hashSet);

        p1.setName("CC");
        System.out.println("查看将p1改为“CC”后的效果:");
        System.out.println(hashSet);

        hashSet.remove(p1);
        System.out.println("查看将p1移除操作后的效果后的效果:");
        System.out.println(hashSet);

        hashSet.add(new Person(1001,"CC"));
        System.out.println("查看将new Person(1001,\"CC\")操作后的效果后的效果:");
        System.out.println(hashSet);

        hashSet.add(new Person(1001,"AA"));
        System.out.println("查看将new Person(1001,\"AA\")操作后的效果后的效果:");
        System.out.println(hashSet);
    }

首先代码初始化了一个HashSet,并将两个相同Person对象p1,p2进行插入;

然后将p1对象的name属性设置为“CC”,重新打印可以看出成功改变名字;

然后调用remove( )方法来尝试移除p1元素,我们可以看到并没有大道预期的效果,原因是在执行remove(p1)操作时的流程是首先调用p1的hashcode( )方法,而在经过改名后,p1的哈希值已经和为改名前的哈希值不一样了,因此借由哈希值来寻址删除也就失败了。

接着进行插入操作hashSet.add(new Person(1001,“CC”));此对象与初始p1的哈希值不同,故插入成功;

最后进行插入操作 hashSet.add(new Person(1001,“AA”));这里可以看到此对象与初始p1一样,因此他们两者的哈希值必定一样,在底层数组的索引位置也是相同的,因此接下来需要进一步调用equals( )方法来确定是否两者属于重复对象,显然equals( )方法必定返回false,因此此操作将插入成功,且是以链表的方式与索引上的元素建立连接。

运行代码效果图如下:
在这里插入图片描述

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值