集合(Set)【3】

集合

1.Set 集合

1.1Set 集合概述和特点

set集合特点

  • 不包含重复元素的集合

  • 没有带索引的方法,所以不能使用普通for循环遍历

Set集合练习

  • 存储字符串并遍历

public class SetDemo {
    public static void main(String[] args) {
        //创建Set对象
        Set<String> set = new HashSet<>();
        //添加元素
        set.add("浪浪");
        set.add("学习");
        set.add("java");
​
        //遍历Set
        for(String s : set){
            System.out.println(s);
        }
    }
}

 

1.2 哈希值

哈希值:是JDK根据对象的地址或者字符串或者数字算出来的int类型的数值

Object类中有一个方法可以获取对象的哈希值

  • public int hashCode():返回对象的哈希码值

对象的哈希值特点

  • 同一个对象多次调用hashCode()方法返回的哈希值是相同的

  • 默认情况下,不同对象的哈希值是不同的。而重写hashCode()方法,可以实现让不同对象的哈希值相同

学生实体类

public class Student {
    private String name;
    private int 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;
    }
​
    public Student() {
    }
​
    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }
}

 

测试类

public class SetDemo {
    public static void main(String[] args) {
        Student s1 = new Student("浪浪",20);
        Student s2 = new Student("王五",20);
        Student s3 = new Student("浪浪",20);
​
        System.out.println(s1.hashCode());//1163157884
        System.out.println(s2.hashCode());//1956725890
        //默认情况下,不同对象的哈希值是不相同的
        //通过方法重写,可以实现不同对象的哈希值是相同的
        System.out.println(s3.hashCode());//356573597
        System.out.println("*****************");
​
        System.out.println("浪浪".hashCode());//896320
        System.out.println("学习".hashCode());//745402
        System.out.println("java".hashCode());//3254818
​
        System.out.println("浪浪".hashCode());//896320
        System.out.println("*******************");
​
​
        System.out.println("重地".hashCode());//1179395
        System.out.println("通话".hashCode());//1179395
    }
}

 

1.3 HashSet集合概述和特点

hashSet集合特点

  • 底层数据结构是哈希表

  • 对集合的迭代顺序不作任何保证,也就是说不保证存储和取出的元素顺序一致

  • 没有带索引的方法,所以不能使用普通for循环遍历

  • 由于是Set集合,所以是不包含重复元素的集合

HashSet集合练习

  • 存储字符串并遍历

1.4 HashSet集合保证元素唯一性源码分析

HashSet集合添加一个元素的过程:

 

 

HashSet集合存储元素:

  • 要保证元素的唯一性,需要重写hashCode 和 equals()

1.4 常见数据结构之哈希表

哈希表

  • JDK8之前,底层采用数组+链表实现,可以说是一个元素为链表的数组

  • JDK8以后,在长度比较长的时候,底层实现了优化

1.5 常见数据结构之哈希表

 

 

案例:HashSet集合存储学生对象并遍历

需求:创建一个存储学生对象的集合,存储多个学生对象,使用程序实现在控制台遍历该集合

要求:学生对象的成员变量值相同,我们就认为是同一个对象

思路:

① 定义学生类

② 创建HashSet集合对象

③ 创建学生对象

④ 把学生添加到集合

⑤ 遍历集合(增强for)

⑥ 在学生实体类中重写hashCode()和equals()方法

学生实体类

public class Student {
    private String name;
    private int 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;
    }
​
    public Student() {
    }
​
    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }
​
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
​
        Student student = (Student) o;
​
        if (age != student.age) return false;
        return name != null ? name.equals(student.name) : student.name == null;
    }
​
    @Override
    public int hashCode() {
        int result = name != null ? name.hashCode() : 0;
        result = 31 * result + age;
        return result;
    }
}

 

 

测试类

public class HashSetDemo {
    public static void main(String[] args) {
        //创建HashSet集合对象
        HashSet<Student> hs = new HashSet<>();
​
        //创建学生对象
        Student s1 = new Student("张三",20);
        Student s2 = new Student("李四",22);
        Student s3 = new Student("王五",21);
        
        Student s4 = new Student("王五",21);
​
        //添加到集合中
        hs.add(s1);
        hs.add(s2);
        hs.add(s3);
        hs.add(s4);
​
        //遍历增强for
        for (Student s : hs){
            System.out.println(s.getName()+","+s.getAge());
        }
    }
}

 

1.6 LinkedHashSet 集合概述和特点

LinkedHashSet集合特点

  • 哈希表和链表实现的Set接口,就有可预测的迭代次序

  • 由链表保证元素有序,就就是说元素的存储和取出顺序是一致的

  • 由哈希表保证元素唯一,也就是说没有重复的元素

LinkedHashSet集合练习

  • 存储字符串并遍历

测试类

public class LinkedHashSetDemo {
    public static void main(String[] args) {
        //创建集合对象
        LinkedHashSet<String> linkedHashSet = new LinkedHashSet<>();
​
        //添加元素
        linkedHashSet.add("浪浪");
        linkedHashSet.add("学习");
        linkedHashSet.add("java");
​
        //由哈希表决定了元素的唯一性
        linkedHashSet.add("java");
        //由链表决定了元素是有序性 元素的存入和读取的顺序是一致的
        for (String s : linkedHashSet
             ) {
            System.out.println(s);
        }
    }
}

 

1.7 TreeSet集合概述和特点

TreeSet集合特点

  • 元素有序,这里的顺序不是指存储和读取的顺序,而是按照一定的规则进行排序,具体排列方式取决于构造器

    • TreeSet():根据其元素的自然排列顺序进行排列

    • TreeSet(Comparator comparator):根据指定的比较器进行排序

  • 没有带索引的方法,所以不能使用普通的for循环遍历

  • 由于是Set集合,所以不包含重复元素的集合

TreeSet集合练习

  • 存储整数并遍历

public class TreeSetDemo {
    public static void main(String[] args) {
        //创建集合对象
        TreeSet<Integer> ts = new TreeSet<>();
​
        //添加元素
        ts.add(10);
        ts.add(40);
        ts.add(35);
        ts.add(15);
        ts.add(66);
​
        ts.add(66);
​
        //遍历集合
        for (Integer i : ts){
            System.out.println(i);
        }
    }
}

 

1.8 自然排序Comparable的使用

  • 存储学生对象并遍历,创建TreeSet集合使用无参构造方法

  • 要求:按照年龄从小到大排序,年龄相同时,按照姓名的字母顺序排序

结论

  • 用TreeSet集合存储自定义对象,无参构造方法使用的是自然排序对元素进行排序的

  • 自然排序,就是让元素所属的类实现Comparable接口,重写compareTo(To)方法

  • 重写方法时,一定要注意排序规则必须按照要求的主要条件和次要条件来写

学生类

public class Student implements Comparable<Student> {
    private String name;
    private int age;
​
    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;
    }
​
    public Student() {
    }
​
    @Override
    public int compareTo(Student o) {
        //return 0;//只插入一条 默认为两个对象一样
        //return 1;//正数 升序
        //return -1;//负数降序
        //按照年龄从小到大排序
        int num = this.age - o.age;
        int num2 = num==0?name.compareTo(o.name):num;
        return num2;
    }
​
}

 

 

测试类

public class TreeSetDemo {
    public static void main(String[] args) {
        //创建集合对象
        TreeSet<Student> ts = new TreeSet<>();
​
        //创建学生对象
        Student s1 = new Student("张三",20);
        Student s2 = new Student("李四",22);
        Student s3 = new Student("王五",21);
        Student s4 = new Student("李六",25);
​
        Student s5 = new Student("歪把七",25);
        Student s6 = new Student("歪把七",25);
​
        //添加到集合中
        ts.add(s1);
        ts.add(s2);
        ts.add(s3);
        ts.add(s4);
        ts.add(s5);
        ts.add(s6);
​
        //集合遍历
        for (Student s : ts){
            System.out.println(s.getName()+","+s.getAge());
        }
    }
}

 

1.9 比较器排序Comparator的使用

  • 存储学生对象并遍历,创建TreeSet集合使用带参构造方法

  • 要求:按照年龄从小到大排序,年龄相同时,按照姓名的字母顺序排序

结论

  • 用TreeSet集合存储自定义对象,带参构造方法使用的是比较器排序对元素进行排序的

  • 比较器排序,就是让集合构造方法接收Comparator的实现类对象,重写compare(T o,T o)方法

  • 重写方法时,一定要注意排序规则必须按照要求的主要条件和次要条件来写

学生实体类

public class Student {
    private String name;
    private int 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;
    }
​
    public Student() {
    }
​
    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }
}

 

 

测试类

public class TreeSetDemo {
    public static void main(String[] args) {
        //创建集合对象
        TreeSet<Student> ts = new TreeSet<>(new Comparator<Student>() {
            @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;
            }
        });
​
        //创建学生对象
        Student s1 = new Student("张三",20);
        Student s2 = new Student("李四",22);
        Student s3 = new Student("王五",21);
        Student s4 = new Student("李六",25);
​
        Student s5 = new Student("歪把七",25);
        Student s6 = new Student("歪把七",25);
​
        //添加到集合中
        ts.add(s1);
        ts.add(s2);
        ts.add(s3);
        ts.add(s4);
        ts.add(s5);
        ts.add(s6);
​
        //集合遍历
        for (Student s : ts){
            System.out.println(s.getName()+","+s.getAge());
        }
​
​
    }
}

 

案例: 成绩排序

需求:用TreeSet集合存储多个学生信息(姓名、语文成绩、数学成绩),并遍历该集合

要求:按照总分从高到底出现

思路:

① 定义学生类

② 创建TreeSet集合对象,通过比较器排序进行排序

③ 创建学生对象

④把学生对象添加到集合

⑤ 遍历集合

学生实体类

public class Student {
    private String name;
    private int chinese;
    private int math;
​
    public Student() {
    }
​
    public Student(String name, int chinese, int math) {
        this.name = name;
        this.chinese = chinese;
        this.math = math;
    }
​
    public String getName() {
        return name;
    }
​
    public void setName(String name) {
        this.name = name;
    }
​
    public int getChinese() {
        return chinese;
    }
​
    public void setChinese(int chinese) {
        this.chinese = chinese;
    }
​
    public int getMath() {
        return math;
    }
​
    public void setMath(int math) {
        this.math = math;
    }
    public int getSum(){
        return this.chinese + this.math;
    }
}

 

 

测试类

public class TreeSetDemo {
    public static void main(String[] args) {
        //创建TreeSet集合对象,通过比较器排序进行排序
        TreeSet<Student> ts = new TreeSet<>(new Comparator<Student>() {
            @Override
            public int compare(Student s1, Student s2) {
                //主要条件
                int num =s1.getSum() - s2.getSum();
                //次要条件
                int num2 = num == 0 ? s1.getChinese()-s2.getChinese():num;
                int num3 = num2 == 0 ? s1.getName().compareTo(s2.getName()):num2;
                return num3;
            }
        });
​
        //创建学生对象
        Student s1 = new Student("张三",98,87);
        Student s2 = new Student("李四",94,92);
        Student s3 = new Student("王五",77,95);
        Student s4 = new Student("李六",90,83);
        Student s5 = new Student("麻子七",70,99);
​
        Student s6 = new Student("崴脚八",75,94);
​
        //添加到数组
        ts.add(s1);
        ts.add(s2);
        ts.add(s3);
        ts.add(s4);
        ts.add(s5);
        ts.add(s6);
​
        //遍历
        for (Student s : ts){
            System.out.println(s.getName()+","+s.getChinese()+","+s.getMath()+","+s.getSum());
        }
    }
}

 

案例: 不重复的随机数

需求:编写一个程序,获取10个1-20之间的随机数,要求随机数不能重复,并在控制台输出

思路:

① 创建Set集合对象

② 创建随机数对象

③ 判断集合的长度是不是小于10

是:产生一个随机数,添加到集合

回到③继续

④ 遍历集合

测试类

public class SetDemo {
    public static void main(String[] args) {
        //创建一个set集合
        //不排序
        //Set<Integer> set = new HashSet<>();
        //排序
        Set<Integer> set = new TreeSet<>();
        //创建一个随机数对象
        Random r = new Random();
​
        //判断集合的长度是否小于10
        while (set.size()<10){
            //产生一个随机数,添加到集合
            int number = r.nextInt(20)+1;
            set.add(number);
        }
​
        //遍历集合
        for (Integer i : set){
            System.out.println(i);
        }
    }
}

 

 

posted @ 2020-09-12 16:55  序猿之途  阅读(195)  评论(0编辑  收藏  举报