问题一:为什么HashSet的存取的顺序不一样?
HashSet在底层实现的机制其实和数据结构与算法课程当中的哈希表机制有点相似,我们知道数据结构与算法课程中的哈希表是已知一个元素的值,通过计算得到的值就是它在数组当中的位置值,即数组下角标,那么HashSet的执行机制也是如此,通过地址值去计算得到的哈希值就是我们应该存放的位置。故然,当我们在程序中添加元素时,虽然有些元素添加是在前面,但是你计算出来的地址值是不一样的,有的位置在前,有的位置在后,所以造成了取出来的顺序就不一样。
问题二:为什么HashSet没有索引?
这个问题我们得先清楚一点,就是HashSet是没有重复元素,以及如何处理数据结构与算法课程中哈希冲突的这个问题,了解了这俩个问题那么就清楚了。
首先,我们讲讲为什么HashSet没有重复元素,前面我们说过了,数据存入HashSet中是先根据地址去计算哈希值然后根据哈希值存入数组,那么如果添加相同元素,这个时候,你要存入数组中,这个位置已经有一个元素了,那么会调用equals方法去比较一下,如果相同,那么就不存入,保留无重复的特性,不同就存入(见下方说明)。
第二,我们在数据结构与算法课程中了解到,存入元素是会有哈希冲突的,什么意思呢?意思是,可能会有其它元素计算出来的哈希值跟之前存入的数据所存入到数组中的下角标冲突了,那么java是如何解决的呢?JDK8之前,是采用了数据+链表的方式去实现,对于哈希值冲突的元素,新元素会存到数组中,那么原来的那些元素就会与新元素形成一个链表。JDK8以后,采用数组+链表+红黑树的方式去解决,原来添加的元素放在数组中的位置是不变的,新元素在下方形成一个红黑树。
所以通过以上了解,我们就清楚为什么没有索引了,比如,假设如果有索引的话,在索引为1的下角标有很多元素,那么我们就不清楚到底取哪个元素了,这就是为什么没有索引的原因。
问题三:如何保证去重?
在底层运用equals和hashCode俩个方法保证去重唯一性,在问题二中我们讲到过,对于相同元素,比较如果相同,那么就不存入,hashCode主要用来去计算出我们元素所应该存入的位置。那么对于自定义的类型数据,重写过后的hashCode会根据对象的内部属性值去计算我们的哈希值,对于内部属性值一样的计算出来的哈希值就是一样的,然后再对应的去调用equals比较是否相同,看是否存入(相同不存,反之)。