上一期我们讲了list集合,它的一个显著特点就是读取速度快,元素可重复,可以自动扩容!!!有一个问题,在上一期中,我们使用foreach去删除元素是会发现在两个相邻的同一样的元素中会发生执行错误,如果我们没有重复相邻的两个元素,再去删除,还是会有问题,但我们如果刚好删除的是倒数第二个元素,就可以正常删除,这是为什么呢,我们一起来看看。
下面的图都为源码:
大家首先看到这里的这个方法,在使用list进行foreach进行删除的时候我们就会进入到这里来,然后进行删除,那具体是怎么样的呢,其实在使用foreach进行删除的时候是调用的一个iterator来进行的,这个迭代器就是我们的array list的内部类中的iterator,它进入到这里之后会调用hasnext方法进行cursor进行一个和集合元素的长度进行比较,如果不相等就还有元素,然后接着往下走,调用next方法先去进行一个检查维护,那这个modCount是什么呢,它其实是我们的集合的大小,当我们集合元素大小发生变化是就会更着改变,例如,如果集合原本大小为5,此时插入一个元素,就变成了6.modCount也变成了6,减少一个变成4,modCount也变成了4。所以我们就会发现,在我们用foreach进行list的删除时这个检查约束过不不了就直接抛出异常了,而为什么倒数第二可以呢,以为删除它就变成倒数第一了,来不及检查约束就已经删除了,其实这也时一个特性,但它本质是一个bug。
检查方法
1. 特点:无序,不重复
2. 遍历:foreach,迭代器
3. 扩容: 初始容量16,负载因子0.75,扩容增量1倍
1.它存储唯一元素并允许空值,依据对象的hashcode来确定该元素是否存在
2. 由HashMap支持
3. 不保持插入顺序
4. 非线程安全
5. 性能参数:初始容量,负载因子,默认值: 初始容量16,负载因子0.75,示例:new HashSet<>(20, 0.5f);
-
- List<Integer> list = new ArrayList<Integer>();
- private Set<Integer> set = new HashSet<Integer>();
-
- @Before
- public void setup() {
- list.add(1);
- list.add(4);
- list.add(4);
- list.add(8);
- list.add(8);
- list.add(12);
- list.add(16);
-
- set.add(1);
- set.add(2);
- set.add(3);
- set.add(3);
- set.add(4);
- set.add(4);
- set.add(5);
-
- }
-
- @Test
- public void setdome01() {
- List<Integer> temp = new ArrayList<Integer>(new HashSet<Integer>(list));
- System.out.println(temp);
- // 结果:[16,1,4,8,12],hashset直接帮我们去重复了,因为set集合不可以出现重复的
- // 除了这种方法还有list的迭代器的去重复,还有最为死的for遍历,一个一个做判断删除
-
- }
-
- // HashSet其实就是一个皮包公司,都是委托
- @Test
- public void setdome02() {
- for (Integer ui : set) {
- System.out.println(ui);
- }
- // 结果:12345;
- // 可以看到,去重复和排序了
- }
-
- @Test
- public void setdome03() {
- Iterator<Integer> it = set.iterator();
- while (it.hasNext()) {
- System.out.println(it.next());
- }
- // 结果:12345
- }
- // 可以看到,我们插入的到顺序是无序的,但我们输出的却是有序的,而set是无序的,
- // 那为什么输出的有序呢,那是因为set的无序指的是插入的顺序是无序 ,而这的有序
- // 是因为hashset的有序,我们常说的有序是指插入的顺序是有序的
1. 是一个包含有序的且没有重复元素的集合
2. 作用是提供有序的Set集合,自然排序或者根据提供的Comparator进行排序
3. TreeSet是基于TreeMap实现的
1.默认自然排序
- 1. 默认自然排序
- 数据准备
-
- ts = new TreeSet<>();
- ts.add(1);
- ts.add(8);
- ts.add(7);
- ts.add(2);
- ts.add(4);
- ts.add(6);
- ts.add(3);
-
-
- @Test
- public void setdome04() {
- Set<Student> set = new HashSet<Student>();
- set.add(new Student(1, "张三", 18));
- set.add(new Student(2, "李四", 19));
- set.add(new Student(3, "李凝", 20));
- set.add(new Student(4, "王三", 21));
- set.add(new Student(4, "王三", 21));
- set.add(new Student(5,"二虎",26));
-
- for (Student student : set) {
- System.out.println(student);
- }
-
- }
2.自定义排序
--1. 较器通过构造函数传入比
- 1. 较器通过构造函数传入比
- TreeSet<Integer> tset = new TreeSet<Integer>(new Comparator<Integer>() {
- @Override
- public int compare(Integer o1, Integer o2) {
- // TODO Auto-generated method stub
- return o2 - o1;
- }
- });
2. 2. 实现排序接口
- public class Student implements Comparable<Student>{
-
- private Integer sid;
-
- private String name;
-
- private int age;
-
-
- @Override
- public int compareTo(Student o) {
- // TODO Auto-generated method stub
- return o.getAge() - this.getAge();
- }
-
- }
-
-
-
- Student实体类
-
- package com.zking.test;
-
- public class Student implements Comparable<Student> {
-
- private Integer sid;
-
- private String sname;
-
- private int age;
-
- public Student(Integer sid, String sname, int age) {
- super();
- this.sid = sid;
- this.sname = sname;
- this.age = age;
- }
-
- public Integer getSid() {
- return sid;
- }
-
- public void setSid(Integer sid) {
- this.sid = sid;
- }
-
- public String getSname() {
- return sname;
- }
-
- public void setSname(String sname) {
- this.sname = sname;
- }
-
- public int getAge() {
- return age;
- }
-
- public void setAge(int age) {
- this.age = age;
- }
-
- @Override
- public int hashCode() {
- final int prime = 31;
- int result = 1;
- result = prime * result + age;
- result = prime * result + ((sid == null) ? 0 : sid.hashCode());
- result = prime * result + ((sname == null) ? 0 : sname.hashCode());
- return result;
- }
-
- @Override
- public boolean equals(Object obj) {
- if (this == obj)
- return true;
- if (obj == null)
- return false;
- if (getClass() != obj.getClass())
- return false;
- Student other = (Student) obj;
- if (age != other.age)
- return false;
- if (sid == null) {
- if (other.sid != null)
- return false;
- } else if (!sid.equals(other.sid))
- return false;
- if (sname == null) {
- if (other.sname != null)
- return false;
- } else if (!sname.equals(other.sname))
- return false;
- return true;
- }
-
- @Override
- public String toString() {
- return "Student [sid=" + sid + ", sname=" + sname + ", age=" + age + "]";
- }
-
- @Override
- public int compareTo(Student o) {
- if (this.getAge() - o.getAge() == 0) {
- return this.getSid() - o.getSid();
- }
- return this.getAge() - o.getAge();
- }
-
- }
set集合元素无放入顺序,且不可重复(注意:元素虽然无放入顺序,但是元素在Set中的位置是由该元素的HashCode决定的,其位置是固定的)。List支持for循环,也就是通过下标来遍历,也可以用迭代器,但是Set只能用迭代器,因为他无序,无法使用下标取值;Set:检索元素效率低,删除和插入效率高,插入和删除不会引起元素位置改变。