集合,准备团战!

前言

        大家好,今天跟大家分享一下java中用的比较多得集合,之前我们学过一个叫Arraylist的集合,这次我们将进入美丽的集合世界。

集合,准备团战!_第1张图片


目录

一 、集合概述

二、List集合

       2.1 list集合概述和特点

三、集合的遍历方法 - 迭代器

四、Set集合

        4.1TreeSet集合概述和特点

        4.2.自然排序Comparable

4.3比较器comparetor的使用

五、HashSet集合

        5.1HashSet集合概述和特点

5.2HashSet集合保证元素唯一性的原理.

      5.3  HashSet实例:

上期问题答案:



一 、集合概述

        所谓集合,就是提供一种存储空间可变的存储模型,存储的数据容量可以随时发生改变。

集合的结构我们首先需要了解,下面这张图就为大家解释了集合的结构。

      集合,准备团战!_第2张图片

 那么我们今天主要了解的就是List集合和Set集合

集合,准备团战!_第3张图片

二、List集合

       2.1 list集合概述和特点


    list集合概述
        - 有序集合(也称为序列),用户可以精确控制列表中每个元素的插入位置。用户可以通过整数索引访问元素,并搜索列表中的元素
        - 与Set集合不同,列表通常允许重复的元素
    list集合特点
        - 有索引
        - 可以存储重复元素
        - 元素存取有序

        学集合,我们应该详细的去了解该集合之中包含的方法,去完成相应的操作

                                                         以下是list集合的常用方法

集合,准备团战!_第4张图片

        那么我们要注意的是List是作为集合接口存在的,也就是说List集合是无法被实例化,通过对象调方法的,那么我们应该想到,多态的方法来完成List集合的实例化,那么有很多类都是List集合的实例对象, 我们只介绍ArrayList集合和LinkedList集合。

        Arraylist集合相信大家在使用他的时候会发现,他跟数组有点像,好像就是数组的无限制版,但其实他的底层就是通过数组结构来实现的,当然他也延续了数组的优秀传统就是查询较快,通过索引,但是他的增删就很慢,这是因为他的每一次查询只需要通过索引获取其值,而他的增删需要其增删的值向被删的位置移动,或者依次移出被插入的元素的位置,这样就导致了我们程序运行的时间较长,就有了我们的LinkedList集合。

        linkedList集合的底层是链表结构实现的,查询慢,增删快。

        那么我们定义了一个集合之后,我们想要输出,除了直接输出集合,如果集合中是存储的基本数据类型的元素,那么会通过他们各自的toString方法输出,那么我们集合当中存储的是一个对象呢?有人说道了,那我们也可以通过重写toString 方法来输出啊。确实,你可以通过重写toString方法,但是,你无法通过如此来get集合当中的每一个元素,如果你不重写toSring方法的话,那么你输出的就是一个地址值,因此我们为了我们的需求,就应该学习集合的遍历方式。

        之前我们学过了ArrayList集合的遍历方式,那是因为其底层是由数组实现的,可以通过数组的方式进行遍历,那么集合有没有属于他专有的遍历方式呢,诶,这你就问对人了,还真有,那就是迭代器。

集合,准备团战!_第5张图片

三、集合的遍历方法 - 迭代器

迭代器的介绍
    - 迭代器,集合的专用遍历方式
    - Iterator iterator():返回此集合中元素的迭代器,通过集合的iterator()方法得到
    - 迭代器是通过集合的iterator()方法得到的,所以我们说它是依赖于集合而存在的

对于迭代器遍历,我们来看一个例子加深一下印象

        

public class IteratorDemo {
    public static void main(String[] args) {
        //创建集合对象
        Collection c = new ArrayList<>();

        //添加元素
        c.add("hello");
        c.add("world");
        c.add("java");
        c.add("javaee");

        //Iterator iterator():返回此集合中元素的迭代器,通过集合的iterator()方法得到
        Iterator it = c.iterator();

        //用while循环改进元素的判断和获取
        while (it.hasNext()) {
            String s = it.next();
            System.out.println(s);
        }
    }
}

 那么该程序就会输出

hello
world
java
javaee

四、Set集合

        4.1TreeSet集合概述和特点


    TreeSet集合概述
        - 元素有序,可以按照一定的规则进行排序,具体排序方式取决于构造方法
              - TreeSet():根据其元素的自然排序进行排序
              - TreeSet(Comparator comparator) :根据指定的比较器进行排序
        - 没有带索引的方法,所以不能使用普通for循环遍历
        - 由于是Set集合,所以不包含重复元素的集合
    TreeSet集合基本使用
      

import java.util.TreeSet;
import java.util.Iterator;

/*
    TreeSet集合特点
        1:元素有序,这里的顺序不是指存储和取出的顺序,而是按照一定的规则进行排序,具体排序方式取决于构造方法
            TreeSet():根据其元素的自然排序进行排序
            TreeSet(Comparator comparator) :根据指定的比较器进行排序
        2:没有带索引的方法,所以不能使用普通for循环遍历
        3:由于是Set集合,所以不包含重复元素的集合
 */
public class TreeSetDemo01 {
    public static void main(String[] args) {
        TreeSet t = new TreeSet();
        t.add(10);
        t.add(20);
        t.add(50);
        t.add(30);
        t.add(40);

        t.add(10);
        //迭代器遍历
        System.out.println("迭代器遍历:");
        Iterator it = t.iterator();
        while (it.hasNext()) {
            int i = it.next();
            System.out.println(i);
        }
        //增强for遍历
        System.out.println("增强for遍历:");
        for (Integer i : t) {
            System.out.println(i);
        }
    }
}

        上述程序的输出结果:

迭代器遍历:
10
20
30
40
50
增强for遍历:
10
20
30
40
50
 

         那么我们可以看到,重复元素10 并没有存入集合,而且上述程序的输出结果是并没有按我们的存入顺序输出,他是按照自然顺序进行排列的,是因为Integer类实现了Comparable接口并且重写了他的compareTo()方法,这里我们可以通过查看源码:

public final class Integer extends Number implements Comparable {
    public int compareTo(Integer anotherInteger) {
        return compare(this.value, anotherInteger.value);
    }
}

        那如果我们自己写了一个类是不是也可以这么做呢?

        4.2.自然排序Comparable

        所谓自然排序,就是让集合元素所属的类实现Comparable接口,并重写compareTo()方法,那么我们的重写规则就是由我们自己定义,但是他的排序是按照比如说数字的大小进行升序或者降序,字母表的排序等等,接下来我们就实战来感受一下:
        案例需求
    - 存储学生对象并遍历,创建TreeSet集合使用无参构造方法
    - 要求:按照年龄从大到小排序,年龄相同时,按照姓名的字母顺序排序

代码示例:

        学生类

public class Student implements Comparable {
    private String name;
    private int age;

    public Student() {
    }

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public int compareTo(Student s) {
//        return -1;
//        int num = this.age - s.age;//升序
        int num = s.age - this.age;//降序
//        return num;
        int num2 = num == 0 ? this.name.compareTo(s.name) : num;
        return num2;
    }
}

        

测试类:

import java.util.TreeSet;

/*
    存储学生对象并遍历,创建集合使用无参构造方法
    要求:按照年龄从小到大排序,年龄相同时,按照姓名的字母顺序排序
 */
public class TreeSetDemo02 {
    public static void main(String[] args) {
        TreeSet t = new TreeSet();

        Student s1 = new Student("张三", 18);
        Student s2 = new Student("李四", 22);
        Student s3 = new Student("王五", 26);
        Student s4 = new Student("刘二", 29);
        Student s5 = new Student("李四", 35);
        Student s6 = new Student("朱三", 29);

        t.add(s1);
        t.add(s2);
        t.add(s3);
        t.add(s4);
        t.add(s6);
        t.add(s5);

        for (Student s : t) {
            System.out.println(s.getName() + "," + s.getAge());
        }
    }
}

输出结果:

李四,35
刘二,29
朱三,29
王五,26
李四,22
张三,18
 

         大家可以看到,我们的输出结果是优先按照年龄的降序来排序的,年龄相同时就按姓名的字母顺序排列,这里我们的重写compareTo()方法就是我们自定义排序的关键

    @Override
    public int compareTo(Student s) {
//        return -1;
//        int num = this.age - s.age;//升序
        int num = s.age - this.age;//降序
//        return num;
        int num2 = num == 0 ? this.name.compareTo(s.name) : num;
        return num2;
    }

        那么String的compareTo()方法如何判定两个变量,并且返回值的呢?感兴趣的大佬可以研究一下源码,我给你们找来了,这里就不多做介绍了。

    public int compareTo(String anotherString) {
        int len1 = value.length;
        int len2 = anotherString.value.length;
        int lim = Math.min(len1, len2);
        char v1[] = value;
        char v2[] = anotherString.value;

        int k = 0;
        while (k < lim) {
            char c1 = v1[k];
            char c2 = v2[k];
            if (c1 != c2) {
                return c1 - c2;
            }
            k++;
        }
        return len1 - len2;
    }

4.3比较器comparetor的使用

         comparetor我们就直接上例子理解,至于源码我这次就不放上了,感兴趣的老铁可以自己在做题的时候,Ctrl + B一下,就能看到。

        案例需求
    - 存储学生对象并遍历,创建TreeSet集合使用带参构造方法
    - 要求:按照年龄从小到大排序,年龄相同时,按照姓名的字母顺序排序

        实现步骤
        - 用TreeSet集合存储自定义对象,带参构造方法使用的是比较器排序对元素进行排序的
        - 比较器排序,就是让集合构造方法接收Comparator的实现类对象,重写compare(T o1,T o2)方法
        - 重写方法时,一定要注意排序规则必须按照要求的主要条件和次要条件来写

       注意:这里实现重写比较器的compare方法可以使用匿名内部类的方法来做,不会的小伙伴也别担心,我给大家提供了传统的实现类方法

        学生类

public class Student {
    private String name;
    private int age;

    public Student() {
    }

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

        学生实现comparetor接口类

    import java.util.Comparator;

/**
 * @author wang
 * @className StudentDemo
 * @date 2021/10/11 15:31
 */
public class StudentDemo implements Comparator {
    //这里演示的是随着年龄升序排序
    @Override
    public int compare(Student s1, Student s2) {
        int num = s1.getAge() - s2.getAge();
        int num2 = num == 0 ? s1.getName().compareTo(s2.getName()) : num;
        return num2;
    }
}

        测试类

    import java.util.Comparator;
import java.util.TreeSet;

/*
    存储学生对象并遍历,创建TreeSet集合使用带参构造方法
    要求:按照年龄从小到大排序,年龄相同时,按照姓名的字母顺序排序
 */
public class TreeSetDemo {
    public static void main(String[] args) {
        //通过多态的形式实现接口
//        Comparator sd = new StudentDemo();
//        //将接口实现类比较器传入集合构造器中,也可直接使用匿名内部类;
//        TreeSet t = new TreeSet(sd);

        //匿名内部类演示随着年龄降序排序
        TreeSet t = new TreeSet(new Comparator() {
            @Override
            public int compare(Student s1, Student s2) {
                int num = s2.getAge() - s1.getAge();
                int num2 = num == 0 ? s1.getName().compareTo(s2.getName()) : num;
                return num2;
            }
        });

        Student s1 = new Student("张三", 18);
        Student s2 = new Student("李四", 22);
        Student s3 = new Student("王五", 26);
        Student s4 = new Student("刘二", 29);
        Student s5 = new Student("李四", 35);
        Student s6 = new Student("朱三", 29);

        t.add(s1);
        t.add(s2);
        t.add(s3);
        t.add(s4);
        t.add(s6);
        t.add(s5);

        for (Student s : t) {
            System.out.println(s.getName() + " " + s.getAge());
        }
    }
}

        输出结果:

李四 35
刘二 29
朱三 29
王五 26
李四 22
张三 18
 

集合,准备团战!_第6张图片

五、HashSet集合

        5.1HashSet集合概述和特点


    HashSet集合的特点
        - 底层数据结构是哈希表
        - 对集合的迭代顺序不作任何保证,也就是说不保证存储和取出的元素顺序一致
        - 没有带索引的方法,所以不能使用普通for循环遍历
        - 由于是Set集合,所以是不包含重复元素的集合
    HashSet集合的基本使用
    

    public class HashSetDemo01 {
    public static void main(String[] args) {
        //创建集合对象
        HashSet hs = new HashSet();

        //添加元素
        hs.add("hello");
        hs.add("world");
        hs.add("java");

        hs.add("world");

        //遍历
        for(String s : hs) {
            System.out.println(s);
        }
    }
}

5.2HashSet集合保证元素唯一性的原理.


   1.根据对象的哈希值计算存储位置
        ​            如果当前位置没有元素则直接存入
        ​            如果当前位置有元素存在,则进入第二步
    ​2.当前元素的元素和已经存在的元素比较哈希值
        ​            如果哈希值不同,则将当前元素进行存储
        ​            如果哈希值相同,则进入第三步
    ​3.通过equals()方法比较两个元素的内容
        ​            如果内容不相同,则将当前元素进行存储
        ​            如果内容相同,则不存储当前元素

这里给大家放一张图方便大家理解

 集合,准备团战!_第7张图片

 那么在实际案例中我们如何去保证集合的元素的唯一性呢?

      5.3  HashSet实例:

        案例需求
    - 创建一个存储学生对象的集合,存储多个学生对象,使用程序实现在控制台遍历该集合
    - 要求:学生对象的成员变量值相同,我们就认为是同一个对象

学生类

import java.util.Objects;

public class Student {
    private String name;
    private int age;

    public Student() {
    }

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "姓名:" + getName() + "\t年龄:" + getAge();
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Student student = (Student) o;
        return age == student.age &&
                Objects.equals(name, student.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, age);
    }
}

测试类

import java.util.HashSet;
import java.util.Iterator;

/*
    需求:
        创建一个存储学生对象的集合,存储3个学生对象,使用程序实现在控制台遍历该集合
        要求:学生对象的成员变量值相同,我们就认为是同一个对象

    思路:
        1:定义学生类
        2:创建HashSet集合对象
        3:创建学生对象
        4:把学生添加到集合
        5:遍历集合(增强for)
 */
public class HashSetDemo02 {
    public static void main(String[] args) {
        HashSet hs = new HashSet();
        Student s1 = new Student("诸葛亮", 20);
        Student s2 = new Student("关羽", 22);
        Student s3 = new Student("刘备", 33);
        Student s4 = new Student("刘备", 33);

        hs.add(s1);
        hs.add(s2);
        hs.add(s3);
        hs.add(s4);

        Iterator it = hs.iterator();
        while (it.hasNext()) {
            Student s = it.next();
            System.out.println(s);
        }
    }
}

输出结果

姓名:诸葛亮    年龄:20
姓名:关羽    年龄:22
姓名:刘备    年龄:33

 可以看到我们有一个重复的元素刘备并没有被存储进来,这就是因为我们在学生类中重写了hashCode方法和equals方法。

上期问题答案:

        D

                100
                100
                200

原因是因为静态成员随着类加载而加载,所以静态成员先输出

你答对了吗?记得点赞关注加三连啊亲!

集合,准备团战!_第8张图片

你可能感兴趣的:(java学习之路,java)