集合(二)

Set集合

  • Set集合特点
    • 不包含重复元素的集合
    • 没有索引的方法,所以不能使用普通for循环遍历
  • Set集合练习
    • 存储字符并遍历
package Set;

import java.util.HashSet;
import java.util.Set;

/*
        Set集合特点:
                不包含重复元素的集合
                没有索引的方法,所以不能使用普通的for循环遍历

        HashSet: 对集合的迭代顺序不做任何保证
*/
public class SetDemo {
    public static void main(String[] args) {
        //创建集合对象
        Set<String> set = new HashSet<String>();

        //添加元素
        set.add("hello");
        set.add("world");
        set.add("java");
        //不包含重复元素的集合
        set.add("world");

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

    }
}

哈希值

  • 哈希值:是JDK根据对象的地址或者字符串或者数字算出来的int类型的数值
  • Object中有一个方法可以获得对象的哈希值
    • public int hashCode(): 返回对象的哈希码值
  • 对象哈希值特点
    • 同一个对象多次调用hashCode()方法返回的哈希值是相同的。
    • 默认情况下,不同对象的哈希值是不同的。而重写的hashCode()方法,可以实现让不同对象的哈希值相同。
package Set;

public class HashDemo {
    public static void main(String[] args) {
        //创建学生对象
        Student s1 = new Student("钟启航",21);
        //通一个对象调用多次hashCode的值是相同的
        System.out.println(s1.hashCode());// 1163157884
        System.out.println(s1.hashCode());// 1163157884

        System.out.println("--------------------------");
        //默认情况下,不同对象的哈希值是不同的
        //通过方法重写,可以实现不同对象的哈希值是相同的
        Student s2 = new Student("芜湖",21);
        System.out.println(s2.hashCode());//1956725890

        System.out.println("---------------------------");

        System.out.println("hello".hashCode());// 99162322
//        System.out.println("hello".hashCode());// 99162322
        System.out.println("world".hashCode());// 113318802
        System.out.println("java".hashCode());// 3254818

        System.out.println("---------------------------");

        System.out.println("重地".hashCode());// 1179395
        System.out.println("通话".hashCode());// 1179395
    }
}

HashSet集合概述和特点

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

import java.util.HashSet;

/*  `   HashSet集合特点
                底层数据结构是哈希表
                对集合的迭代顺序不作任何保证,也就是说不保证存储和取出的元素顺序一致
                没有带索引的方法,所以不能使用普通for循环遍历
                由于是Set集合,所以是不包含重复元素的集合*/
public class HashSetDemo1 {
    public static void main(String[] args) {
        //创建集合对象
        HashSet<String> hs = new HashSet<String>();

        hs.add("hello");
        hs.add("world");
        hs.add("java");

        hs.add("world");

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

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

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

 

 

HashSet集合存储元素

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

 

常见数据结构之哈希表

  • 哈希表
    • JDK8 之前,底层采用数组+链表实现,可以说是一个元素为链表的数组
    • JDK8以后,在长度比较长的时候,底层实现了优化

 

 

 

  

 

 

 

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

  • 需求: 创建一个存储学生对象的集合,存储多个学生对象,使用程序实现控制台遍历该集合
  • 要求: 学生对象的成员变量值相同,我们认为就是同一个对象
  • 思路
    • 1.定义学生类
    • 2.创建HashSet集合对象
    • 3.创建学生对象
    • 4.把学生添加到集合
    • 5.遍历集合(增强for)
    • 最后补充:在Student类中重写hashCode()和equals()方法。
public class HashDemo2 {
    public static void main(String[] args) {
        HashSet<Student> hs = new HashSet<Student>();

        Student s1 = new Student("芜湖",21);
        Student s2 = new Student("uahu",22);
        Student s3 = new Student("wuhu",23);
        Student s4 = new Student("meih",22);

        Student s5 = new Student("meih",22);

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

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

    }
}

注意:如何使数据具有唯一性?

  • 在Student类中重写hashCode()和equals()方法。
package Set;

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 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;
    }
}

 LinkedHashSet集合概述和特点

  • LInkedHashSet集合概述和特点
    • 哈希表和链表实现的Set接口,具有可预测的迭代次序
    • 由链表保保证元素有序,也就是说元素的存储和取出顺序是一样的
    • 由哈希表保证元素唯一,也就是说没有重复的元素。 
  • LinkedHashSet集合练习
    • 存储字符串并遍历
package Set;

import java.util.LinkedHashMap;
import java.util.LinkedHashSet;

public class LInkedHashDemo1 {
    public static void main(String[] args) {
        LinkedHashSet<String> linkedHashSet = new LinkedHashSet<String>();

        linkedHashSet.add("钟启航");
        linkedHashSet.add("21");
        linkedHashSet.add("芜湖");
        linkedHashSet.add("21");

        for (String s : linkedHashSet){
            System.out.println(s);
        }
    }
}

TreeSet集合概述和特点

  • TreeSet集合特点
    • 元素有序,这里的顺序不是指存储和取出的顺序,而是按照一定的规则进行排序,具体排序方式取决于构造方法。
      • TreeSet():根据其元素的自然排序进行排序
      • TreeSet(Comparator comparator):根据指定的比较器进行排序
    • 没有带索引的方法,所以不能使用普通For循环遍历,可以使用迭代器和增强For
    • 由于是Set集合,所以不包含重复元素的集合
  • TreeSet集合练习
    • 存储整数并遍历
package Set;

import org.omg.PortableInterceptor.INACTIVE;

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

public class TreeSetDemo1 {
    public static void main(String[] args) {
        //创建集合
//        TreeSet<String> treeSet = new TreeSet<String>();
        TreeSet<Integer> treeSet = new TreeSet<Integer>();
        

        treeSet.add(35);
        treeSet.add(50);
        treeSet.add(45);

//        Iterator<Integer> iterator = treeSet.iterator();
//        while (iterator.hasNext()){
//            Integer next = iterator.next();
//            System.out.println(next);
//        }

        for (Integer t : treeSet){
            System.out.println(t);
        }
    }
}

自然排序Comparable的使用

  • 存储对象并遍历,创建TreeSet集合使用无参构造方法
    • 要求:按照年龄从小到大排序,年龄相同时,按照姓名的字母顺序排序
  • 该接口对实现它的每个类的对象强加一个整体排序。 这个排序被称为类的自然排序 ,类的compareTo方法被称为其自然比较方法 。 所以这个练习需要在Student类中实现接口Comparable<>,在Student类中重写compareTo()方法。
  • 结论
    • TreeSet集合存储自定义对象,无参构造方法使用的是自然排序,对元素进行排序的
    • 自然排序,就是让元素所属的类实现Comparable接口,重写compareTo(T o)方法
    • 重写方法时,一定要注意排序规则必须按照要求的主要条件和次要条件来写

Student类

package Set;

import java.util.TreeSet;

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

        Student s1 = new Student("xishi",21);
        Student s2 = new Student("wuhu",24);
        Student s3 = new Student("yahu",22);
        Student s4 = new Student("meihu",26);

        Student s5 = new Student("lingqingxia",26);
        Student s6 = new Student("lingqingxia",26);

        //添加到集合
        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);
        }
    }
}

比较器排序Comparator的使用

  • 存储学生对象并遍历,创建TreeSet集合使用带参构造方法
    • 要求:按照年龄从小到大排序,年龄相同时,按照姓名的字母顺序排序
  • 结论
    • 用TreeSet集合存储自定义对象,带参构造方法使用的是比较器排序对元素进行排序的
    • 比较器排序,就是让集合构造方法接收Comparator的实现类对象,重写compare(T o1,T o2)方法
    • 重写方法时,一定要注意排序规则必须按照要求的主要条件和次要条件来写
package Set;

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

public class ComparatorDemo1 {
    public static void main(String[] args) {
        //创建集合对象
        TreeSet<Student> ts = new TreeSet<Student>(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("xishi",21);
        Student s2 = new Student("wuhu",24);
        Student s3 = new Student("yahu",22);
        Student s4 = new Student("meihu",26);

        Student s5 = new Student("lingqingxia",26);
        Student s6 = new Student("lingqingxia",26);

        //添加到集合
        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);
        }
    }
}

 

 案例:成绩排序

  • 需求:用TreeSet集合存储多个学生信息(姓名,语文成绩,数学成绩),并遍历该集合
    • 要求:按照总分从高到低出现
  • 思路
    • 定义学生类
    • 创建TreeSet对象,通过比较器排序进行排序
    • 创建学生对象
    • 把学生对象添加到集合
    • 遍历集合
package Set;

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

/*
    需求:用TreeSet集合存储多个学生信息(姓名,语文成绩,数学成绩),并遍历该集合
        要求:按照总分从高到低出现
        思路
            定义学生类
            创建TreeSet对象,通过比较器排序进行排序
            创建学生对象
            把学生对象添加到集合
            遍历集合
*/
public class StudentDemo2 {
    public static void main(String[] args) {
        TreeSet<Student3> ts = new TreeSet<Student3>(new Comparator<Student3>() {
            @Override
            public int compare(Student3 s1, Student3 s2) {
                int num = (s2.getChineseperformance()+s2.getMathperformance())-(s1.getChineseperformance()+s1.getMathperformance());//也可以在Student类中定义一个Sum,这里不进行定义了。
                int num2 = num ==0 ?s1.getName().compareTo(s2.getName()): num;//也可以使用语文或者数学成绩在排名,但是得吧语文数学以及姓名排序都写上以防成绩完全相同无法写入。
                return num2;
            }
        });

        Student3 s1 = new Student3("钟启航",89,100);
        Student3 s2 = new Student3("方世涛",90,95);
        Student3 s3 = new Student3("张益磊",60,120);
        Student3 s4 = new Student3("凯",50,100);
        Student3 s5 = new Student3("虎",60,60);
        Student3 s6 = new Student3("zhong",70,90);

        Student3 s7 = new Student3("yihu",70,90);
        //添加到集合
        ts.add(s1);
        ts.add(s2);
        ts.add(s3);
        ts.add(s4);
        ts.add(s5);
        ts.add(s6);
        ts.add(s7);

        for (Student3 s : ts){
            System.out.println(s);
        }
    }
}

案例:

  • 不重复的随机数
    • 需求:编写一个程序,获取10个1-20之间的随机数,要求随机数不能重复,并在控制台输出
    • 思路
      • 创建Set集合对象
      • 创建随机数对象
      • 判断集合长度是不是小于10
        • 是:产生一个随机数,添加到集合 
        • 再次执行上一步
      • 遍历集合
package Set;

import java.util.HashSet;
import java.util.Random;
import java.util.Set;
import java.util.TreeSet;

/*
    不重复的随机数
        需求:编写一个程序,获取10个1-20之间的随机数,要求随机数不能重复,并在控制台输出
        思路
            创建Set集合对象
            创建随机数对象
            判断集合长度是不是小于10
            是:产生一个随机数,添加到集合
            再次执行上一步
            遍历集合
*/
public class TestDemo2 {
    public static void main(String[] args) {
        //创建set集合
//        Set<Integer> set = new HashSet<Integer>(); //最终结果不会排序
        Set<Integer> set = new TreeSet<Integer>();  //最终结果会进行一个简单的排序
        //创建随机数对象
        Random r = new Random();

        //判断集合是否小于10  Set集合不能有重复元素,所以相同的随机数不会加入到Set集合中
        while (set.size()< 10){
            int num = r.nextInt(20) + 1;
            set.add(num);
        }
        for (Integer i : set){
            System.out.println(i);
        }
    }
}

 

posted @ 2021-08-09 22:37  钟心意  阅读(48)  评论(0)    收藏  举报