一、Set

无序、不可重复的数据。但这里的无序跟遍历的顺序不是一个意思。

        

Set接口框架

  • HashSet:作为Set的主要实现类;线程不安全;可以存储null值。
  • LinkedHashSet:作为HashSet的子类,在遍历数据时可以按添加的顺序遍历。
  • TreeSet:底层为红黑树,可以按照添加对象的指定属性,进行排序。

无序性和不可重复性的理解

以HashSet为例说明:

  • 无序性:不等于随机性。存储的元素在底层数组中并非按照数组索引的顺序添加,而是根据元素的哈希值决定的。
  • 不可重复性:保证添加的元素按照equals()判断时,不能返回true。即相同的元素只能添加一个。

添加元素的过程

以HashSet为例说明:

  1. 向HashSet中添加a,首先调用元素a所在类的hashCode()方法,计算元素a的哈希值。
  2. 此哈希值接着通过某种算法计算出在HashSet底层数组中的存放位置(即索引值),判断数组此位置上是否已经有元素:
  1. 如果此位置没有其他元素,则a元素添加成功。情况①
  2. 如果此位置上有其他元素b(或以链表形式存在的多个元素),则比较元素a与元素b的hash值:
  1. 如果hash值不相同,则元素a添加成功。情况②
  2. 如果hash值相同,进而需要调用元素a所在类的equals()方法:
  1. equals()返回true。元素a添加失败。
  2. equals()返回false。元素a添加成功。情况③

        对于添加成功的情况②和情况③而言:元素a与已经存在指定索引位置上的数据,以链表的方式进行存储。

        jdk7:新元素放到数组中,指向原来的元素。[元素n]—>.....—>元素1

        jdk8:原来的元素在数组中,指向新元素。[元素1]——>.....—>元素n

        总结:七上八下。

java无序列表类 java 无序可重复_java无序列表类

                  

Eclipse/IDEA工具中hashCode()的重写

        在自定义类中可以调用工具自动重写equals和hashCode。

        Q:为什么Eclipse/IDEA工具中重写hashCode(),有31这个数字?

  • 选择系数的时候选择尽量大的系数。因为如果计算出来的hash地址越大,所谓的"冲突“就越少,查找起来的效率也会提高。(减少冲突)
  • 并且31只占5bits,相乘造成数据溢出的概率较小。
  • 31可以由i*31=(i<<5)-1表示,现在很多虚拟机里面都有做相关优化。(提高算法效率)
  • 31是一个素数,素数作用就是如果我用一个数字来乘以这个素数,那么最终出来的结果只能被素数本身和被乘数还有1来整除。(减少冲突)

总结

  1. Set接口中没有额外定义新方法,使用的都是Collection中声明过的方法。
  2. 要求:向Set中添加的数组,其所在的类一定要重写hashCode()equals()。以实现对象相等规则,即“相等的对象必须具有相等的散列码”。

LinkedHashSet

        作为HashSet的子类,在添加数组的同时,每个数据还维护了两个引用,以记录此数据的前一个数组和后一个数据。

        优点:对于频繁的遍历操作,LinkedHashSet效率高于HashSet。


TreeSet

  1. 向TreeSet中添加的数据,要求是相同类的对象。
  2. 两种排序方式:自然排序 和 定制排序。

1.自然排序(实现Comparable接口)

compareTo()返回0,不再是equals()

2.定制排序()

compare()返回0,不再是equals()

java无序列表类 java 无序可重复_java_02