各位小伙伴们大家好,欢迎来到这个小扎扎的《Java核心技术 卷Ⅰ》笔记专栏,在这个系列专栏中我将记录浅学这本书所得收获,鉴于 看到就是学到、学到就是赚到 精神,这波简直就是血赚
💡涉及的知识点速通
- 🛫 关于Set集合类你都知道什么?
- 🪂 如何理解Set集合元素的无序不可重复?
- 🪂 如何重写equals和hashCode方法?
- 🪂 HashSet和LinkedHashSet的异同?
- 🪂 TreeSet都需要注意哪些?
- 🪂 集合和数组之间如何相互转换?
- 🛫 Collection集合类的关系图
🛫 关于Set集合类你都知道什么?
我们将实现了Set接口的类称为是List集合类,List集合类中元素存储有一个特点:无序、不可重复,Set接口常用的有三个实现类:HashSet、linkedHashSet、TreeSet
🪂 如何理解Set集合元素的无序不可重复?
无序性: 以HashSet集合为例,HashSet底层创建的是HashMap,而HashMap最主要的数据结构就是散列表,java使用链表数组来实现散列表,也就是一种数组加链表的结构,在这里数组中的每个元素被称为是桶(bucket,默认为16)。所谓的元素无序存储指的是:存储的元素并不是按照索引顺序依次存入数组,而是使用哈希算法也就是将元素的散列码(hash值)对桶数进行取模运算,得到的结果就是该元素在数组中存储的索引位置 Object类中定义的有hashCode方法可以获取该对象对应的散列码(hash值),又因为Object类是所有类的超类,所以每一个类的对象都能通过hashCode方法获取到它所对应的散列码,但是值得注意的是:使用hashCode生成的散列码不同意味着它们肯定不相等,但是散列码相等并不就意味着它们一定相等,所以说如果想要判断它们是否相等需要再进行equals对比,如果equals的结果也为true的话表示它们一定相等
不可重复性: 这里我们同样以HashSet集合为例,散列码相同的元素一定会被分到数组的同一个索引位置进行存储,此时如果我们再判断一下新添加的元素与该索引位置上链表元素的散列码是否相等,如果相等再进行equals比较,如果还相等则说明新增元素是个重复元素,这样的话就可以保证set集合中的元素不会重复了
元素添加顺序: 在jdk7和jdk8中新元素的添加顺序也是不一样的,在jdk7中是新元素 “上位” 指向链表中原来最新的元素;而jdk8中则是将新元素 “下位” 放在链表的末尾,原来最新的元素指向新元素。可以使用成语 “七上八下” 方便记忆
🪂 如何重写equals和hashCode方法?
众所周知的是,Object类是所有类的超类,所以说如果在不重写equals和hashCode方法的情况下,set集合判断添加的是否是重复元素使用的就是Object类中的equals和hashCode方法,但是Object中的equals方法比较的是地址值、hashCode方法是通过地址值生成一个hash值。由此可见,即使自定义类的属性值都一样依然会被set集合识别为非重复值,因为他们存储的地址不同。所以说,自定义类如果使用到hash结构的话,最好重写equals和hashCode方法
重写后的equals和hashCode方法要尽量保持结果一致,也就是说当equals结果为true的时候hashCode的散列码也要相等,那么如何做到这一点呢?那就是在重写这两种方法进行比较或者生成hash值的时候,尽量使用相同的字段,这里可以参考IDEA中默认重写的equals和hashCode的写法
🪂 HashSet和LinkedHashSet的异同?
三者相同点:HashSet、LinkedHashSet和TreeSet都实现了Set接口,所以它们存储数据的特点都一致,那就是无序、不可重复。而且Set接口中并没有额外定义新的API方法,也就是说Set集合类中的API都是从Collection接口中继承过来的
HashSet是LinkedHashSet的父类,HashSet和LinkedHashSet中可以存储null元素,而且这两种set集合都是线程不安全的。除此之外,二者的差距就是LinkedHashSet在HashSet的基础上又可以将所有的元素按照存入的顺序遍历出来,这并不就意味着LinkedHashSet中存储的元素就是有序的,而是它在HashSet底层散列表的基础上又使用双向链表将元素按照顺序前后链接起来,当遍历集合元素的时候就可以顺着双向链表依次输出
🪂 TreeSet都需要注意哪些?
首先TreeSet不可以存储null元素,否则就会抛出NullPointerException异常。其次TreeSet可以将添加的元素进行排序,但是添加进来的必须是相同类型的元素,否则就会抛出ClassCastException异常 在类型一致的情况下,如果添加的元素是自定义类型的话,必须手动定义排序规则,定义的方式主要有两种
第一种是自然排序,即实现Comparable接口重写compareTo方法,在方法中指定TreeSet集合元素排序的规则,具体使用可以参考下面的截图 第二种是定制排序,即创建TreeSet集合对象时向参数中传递一个comparator对象,该对象应该重写compare方法并指定排序规则,具体使用可以参考下面的截图 从上面两个例子可以得知一个十分重要的结论:TreeSet集合判断元素是否重复的规则不再是equals加hashCode方法,而是compareTo方法或者compare方法的返回值,返回值为零则说明元素重复,无法添加到集合中。
🪂 集合和数组之间如何相互转换?
集合转数组
使用Collection接口里的toArray方法,可以将集合转成一个object数组,而且还可以使用数组对象作为参数指定转换的数组类型数组转集合
数组转List集合的话可以使用Arrays的asList方法,转成其他集合的话应该使用循环将数组中的元素依次添加到空集合中,并没有现成的API可以使用由此可见,Arrays中的asList方法将基本数据类型数组对象当成一个元素转换成List集合,但是该类型对应的包装类数组是将数组中的数据对象当成一个元素转换成List集合
🛫 Collection集合类的关系图
至此,我们已经学习了整个Collection集合的常用实现类,在这里我整理了一下Collection集合的关系图谱供大家参考学习