关于HashSet的存储原理
关于HashSet的存储原理1.HashSet是Java容器中的一种具体实现,可以用来存储无序且不重复的元素:1.无序性:不等于随机性。存储的数据在底层素组中并非按照素组索引的顺序添加,而是根据数据的哈希值来决定数据存储的位置。2.不可重复性:保证添加的元素以equals()判断是不能返回true。即相同的元素只能添加一个。2.HashSet中元素的添加过程:我们向HashSet中添加元素a
关于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,因此此操作将插入成功,且是以链表的方式与索引上的元素建立连接。
运行代码效果图如下:
更多推荐
所有评论(0)