Set接口
如果有人告诉你Set是无序的,那你可以直接回怼他这是错的,说法不严谨。
Set接口的实现类(都不能放重复值)
1.HashSet(无序)
2.LinkedHashSet(有序)
3.TreeSet(有序)
没有ArraySet,这是因为Array是连续的,Set是不连续的;
-
Set与List的相同点,也是Collection的子接口,也是容器
-
Set才叫真正意义上的集合,List叫做列表
-
集合与列表的区别:
列表是一条一条记录的,而集合是围在一起的
比如,有五个人,他们整整齐齐做一列就是列表,要是围一堆坐着就是集合,不知道谁是头,谁是尾
Set集合是没有脚标的,所以Set里面也没有get方法,List有脚标,所以可以有get方法,List和Set是兄弟关系,这也正是Collection接口里没有get方法的原因。
-
集合中不能放重复的对象,这是因为他没有脚标。所以Set集合可用来去重
-
Set有点像水壶,茶壶里煮饺子,倒不出来。要是想从Set里拿出来,则必须把所有的值都拿出来
HashSet是无序的,注意是HashSet不是Set
forezch在底层使用迭代器实现的
如果一个类没有迭代器,则它不能使用foreach循环
iterator.remove();不能连着使用
-
怎么解释hashset是无序的,怎么解释set不能放重复元素?
因为hashSet的底层是按照hash算法排列得到的数列,他是一个不可逆的算法。每个对象都有一个hashcode,hash算法通过hashcode来排数据,所以hashset无序。
HashSet底层由HashMap实现,插入的元素被当做是HashMap的key,根据hashCode值来确定集合中的位置,在向HashMap中添加元素时,先判断key的hashCode值是否相同,如果相同,则调用equals()、==进行判断,若相同则覆盖原有元素;如果不同,则直接向Map中添加元素;
set的两个主要实现类,TreeSet和HashSet,底层存储结构都是用的map,而且是将set需要存储的值放在map的key里的,value是一个空的object对象。
-
那有没有有序的set呢
有,LinkedHashSet, 往里放的什么顺序,打印出来的就是什么顺序,以链表的形式存当前的元素,只是链表位置被hash了,但是它没有下标
还有一个有序的set,TreeSet。按comparable升序排列,它的底层实现是二叉树
TreeSet有个约束,往它里面放到内容必须实现comparable接口
一、HashSet
在向HashMap中添加元素时,先判断key的hashCode值是否相同,如果相同,则调用equals()、==进行判断,若相同则覆盖原有元素;如果不同,则直接向Map中添加元素;
public class Main {
public static void main(String[] args) {
Set<String> sets = new HashSet<>();
sets.add("zhang");
sets.add("ao");
sets.add("qi");
sets.add("zhang");
sets.add("san");
Iterator<String> iterator = sets.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
} //输出:san qi zhang ao //无序的且不重复
sets.remove("ao");//删除元素
sets.clear(); //清空容器
}
}
二、LinkedHashSet(直接父类是 HashSet)
特点:存取有序,存储的元素不能重复。
Set<String> sets = new LinkedHashSet<>();
sets.add("a");
sets.add("a");
sets.add("a");
sets.add("b");
sets.add("b");
sets.add("c");
sets.add("d");
for (String str:sets
) {
System.out.println(str);
}
//输出a b c d
三、TreeSet( 底层结构为红黑树 )
与HashSet不同的是,TreeSet具有排序功能,分为自然排序(123456)和自定义排序两类,默认是自然排序;在程序中,我们可以按照任意顺序将元素插入到集合中,等到遍历时TreeSet会按照一定顺序输出–倒序或者升序;
方式一: 让元素所在的类实现Comparable接口,并重写CompareTo() 方法,并根据CompareTo()的返回值来进行添加元素
- 返回正数:往二叉树的右边添加
- 返回负数:往二叉树的左边添加
- 返回 0 : 说明重复,不添加
方式二: 使用TreeSet的有参构造方法创建TreeSet对象的时候, 传入一个比较器 Comparator 进去, TreeSet在添加元素的时候, 根据比较器的compare()方法的返回值来添加元素。
- 返回正数:往二叉树的右边添加
- 返回负数:往二叉树的左边添加
- 返回 0 : 说明重复,不添加
TreeSet存储元素对元素进行排序的源码解析
TreeSet在存储元素的时候会首先去判断是否有比较器存在(也就是判断比较器是否为null),如果存在:就会让比较器去调用compare(T t1, T t2)方法,去依次比较即将存入的值和已经存入TreeSet集合的值,如果返回正数:往二叉树右侧放;如果返回负数:往二叉树左侧放;如果返回 0 :不添加。如果不存在:底层就会把即将存入的元素自动提升为Comparable类型的对象(所以如果没有比较器的情况下,元素所在的类没有实现Comparable接口,在做自动提升类型的时候就会报类型转换错误),并让该对象调用CompareTo(T t)方法,和已经存入TreeSet集合的元素依次比较,如果返回正数:往二叉树右侧放;如果返回负数:往二叉树左侧放;如果返回 0 :不添加。所以,如果两种方式同时使用,底层会优先使用方式二(比较器的方式)。
学习参考:
https://blog.csdn.net/Qingai521/article/details/87968134
https://www.baidu.com/link?url=o4mGbw9BArl9kO8SxYj_9jYdwjO5FsfggK8FpB6CCxsj1SxlIhSRsx7_3mAu_2F3&wd=&eqid=a848f8fb0007e998000000035dfaf2c7
来源:CSDN
作者:沉默菜鸟张
链接:https://blog.csdn.net/ysf15609260848/article/details/103612529