Java类集框架-Set
Set集合
Set集合概述和特点
-  不可以存储重复元素 
-  存取的顺序不一致 
-  没有索引,不能使用普通for循环遍历 

代码实现
案例:存储字符串并遍历
public class Demo{
    public static void main(String[] args) {
      	//创建集合对象
        Set<String> set = new TreeSet<>();
      	//添加元素
        set.add("ccc");
        set.add("aaa");
        set.add("aaa");
        set.add("bbb");
      
      	//(1)遍历集合
        Iterator<String> it = set.iterator();
        while (it.hasNext()){
            String s = it.next();
            System.out.println(s);
        }
        System.out.println("-----------------------------------");
        
        //(2)遍历集合
        for (String s : set) {
            System.out.println(s);
        }
    }
}遇到重复元素, set集合会自动帮我们去重!
Set集合的实现——TreeSet
特点
-  不可以存储重复元素 
-  没有索引 
-  可以将元素按照规则进行排序 -  TreeSet():根据其元素的自然排序进行排序 
-  TreeSet(Comparator comparator) :根据指定的比较器进行排序 
 
-  
(1)自然排序-Comparable
按照字典序,进行排序。
public class Demo03 {
    public static void main(String[] args) {
        TreeSet<String> ts = new TreeSet<>();
        ts.add("aaa");
        ts.add("bb");
        ts.add("cc");
        ts.add("dd");
        ts.add("a");
        System.out.println(ts);
        //[a, aaa, bb, cc, dd]
    }
}案例(一):
存储学生对象并遍历,创建TreeSet集合使用无参构造方法
要求:按照年龄从小到大排序,年龄相同时,按照姓名的字母顺序排序
实现步骤:
- 使用空参构造创建TreeSet集合。用TreeSet集合存储自定义对象,无参构造方法使用的是自然排序对元素进行排序的
- 自定义的Student类实现Comparable接口。自然排序,就是让元素所属的类实现Comparable接口,重写compareTo(T o)方法
- 重写接口中的compareTo方法。重写方法时,一定要注意排序规则必须按照要求的主要条件和次要条件来写
代码实现:
public class Demo03 {
    public static void main(String[] args) {
        TreeSet<Student> stu = new TreeSet<>();
        Student s1 = new Student("小花花",27);
        Student s2 = new Student("小花",29);
        Student s3 = new Student("小明",25);
        Student s4 = new Student("小黑",25);
        stu.add(s1);
        stu.add(s2);
        stu.add(s3);
        stu.add(s4);
        System.out.println(stu);
        //[Student{name='小明', age=25}, Student{name='小花花', age=27}, Student{name='小花', age=29}]
    }
}public class Student implements Comparable<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 "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
    
    @Override
    public int compareTo(Student o) {
        int result = this.age - o.age;
        return result;
    }
}
上述代码中,需要深究的是我们重写的comparaTo方法
@Override
public int compareTo(Student o) {
int result = this.age - o.age;
return result;
}

案例(二):
在上述案例(一)的基础上,进行改进
存储学生对象并遍历,创建TreeSet集合使用无参构造方法
要求:按照年龄从小到大排序,年龄相同时,按照姓名的字母顺序排序
代码实现
上述其他的代码不变,只要修改comparaTo()中的内容
@Override
public int compareTo(Student o) {
    int result = this.age - o.age;
    result = result == 0 ? this.name.compareTo(o.getName()) : result;
    return result;
}
关于comparaTo()方法在菜鸟编程上有这样子的解释

(2)按照指定的比较器排序-Comparator
- TreeSet的带参构造方法使用的就是比较器排序对元素进行排序
- 比较器排序,就是让集合构造方法接收Comparator的实现类对象,重写compara(T o1,To2)方法。
- 重写方法时,一定要注意排序规则必须按照要求的主要条件和次要条件来写。
案例分析:
依然使用上述案例的环境,使用Comparator的方式实现
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 "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}public class Demo03 {
    public static void main(String[] args) {
        TreeSet<Student> stu = new TreeSet<>(new Comparator<Student>() {
            @Override
            public int compare(Student o1, Student o2) {
                //o1表示现在要存入的那个元素
                //o2表示已经存入到集合中的元素
                //主要条件
                int result = o1.getAge() - o2.getAge();
                //次要条件
                result = result == 0 ?  o1.getName().compareTo(o2.getName()) :result;
                return result;
            }
        });
        Student s1 = new Student("小花花",27);
        Student s2 = new Student("小花",29);
        Student s3 = new Student("小明",25);
        Student s4 = new Student("小黑",25);
        stu.add(s1);
        stu.add(s2);
        stu.add(s3);
        stu.add(s4);
        System.out.println(stu);
    }
}两种比较方式小结
自然排序: 自定义类实现Comparable接口,重写compareTo方法,根据返回值进行排序
比较器排序: 创建TreeSet对象的时候传递Comparator的实现类对象,重写compare方法,根据返回值进行排序
在使用的时候,默认使用自然排序,当自然排序不满足现在的需求时,必须使用比较器排序
两种方式中关于返回值的规则
如果返回值为负数,表示当前存入的元素是较小值,存左边
如果返回值为0,表示当前存入的元素跟集合中元素重复了,不存
如果返回值为正数,表示当前存入的元素是较大值,存右边
案例-比较字符串
按照长度排序,如果长度一样则按照首字母排序!
实现方式一:
public class Demo {
    public static void main(String[] args) {
        TreeSet<String> ts = new TreeSet<>(new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
                int result = o1.length() - o2.length();
                result = result == 0 ? o1.compareTo(o2) : result;
                return result;
            }
        });
        ts.add("d");
        ts.add("asd");
        ts.add("gre");
        ts.add("zfsdfsf");
        System.out.println(ts);
        //[d, asd, gre, zfsdfsf]
    }
}实现方式二:
public class Demo {
    public static void main(String[] args) {
        TreeSet<String> ts = new TreeSet<>(
                (String o1,String o2) -> {
                    int result = o1.length() - o2.length();
                    result = result == 0 ? o1.compareTo(o2) : result;
                    return result;
                }
        );
        ts.add("d");
        ts.add("asd");
        ts.add("gre");
        ts.add("zfsdfsf");
        System.out.println(ts);
        //[d, asd, gre, zfsdfsf]
    }
}Set集合的实现——HashSet
特点
-  底层数据结构是哈希表 
-  存取无序 
-  不可以存储重复元素 
-  没有索引,不能使用普通for循环遍历 
基本使用
public class Demo {
    public static void main(String[] args) {
        //创建集合对象
        HashSet<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);
            //world
            //java
            //hello
        }
    }
}哈希值
哈希值简介
是JDK根据对象的地址或者字符串或者数字算出来的int类型的数值
如何获取哈希值
Object类中的public int hashCode():根据对象的地址值,返回计算出的哈希值
Coding
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(String name, int age) {
        this.name = name;
        this.age = age;
    }
    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
public class HashCodeDemo {
    public static void main(String[] args) {
        Student s1 = new Student("zhangsan",19);
        Student s2 = new Student("xiaoming",78);
        System.out.println(s1.hashCode());
        //356573597
        System.out.println(s2.hashCode());
        //1735600054
        System.out.println(s1.hashCode());
        //356573597
    }
}上述代码演示,使用实例化Student对象s1,s2,它们调用hashCode()方法,根据创建的对象的地址返回它们对应的hash值。
我们可以查看IDEA中的hashCode的模板
@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);
}当然我们可以对上述模板行进重写,就一般是根据对象的属性值来计算哈希值。此时,跟对象的地址值就没有关系。
哈希值的特点
同一个对象多次调用hashCode()方法返回的哈希值是相同的
默认情况下,不同对象的哈希值是不同的。而重写hashCode()方法,可以实现让不同对象的哈希值相同
哈希表结构
JDK1.8以前

JDK1.8之后

关于红黑树的详细介绍如下所示:
二叉树之红黑树 https://blog.csdn.net/weixin_43715214/article/details/122811540
https://blog.csdn.net/weixin_43715214/article/details/122811540
HashSet集合存储学生对象并遍历
案例需求
创建一个存储学生对象的集合,存储多个学生对象,使用程序实现在控制台遍历该集合
要求:学生对象的成员变量值相同,我们就认为是同一个对象
代码实现
学生类
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;
    }
}测试类
public class HashSetDemo02 {
    public static void main(String[] args) {
        //创建HashSet集合对象
        HashSet<Student> hs = new HashSet<Student>();
        //创建学生对象
        Student s1 = new Student("林青霞", 30);
        Student s2 = new Student("张曼玉", 35);
        Student s3 = new Student("王祖贤", 33);
        Student s4 = new Student("王祖贤", 33);
        //把学生添加到集合
        hs.add(s1);
        hs.add(s2);
        hs.add(s3);
        hs.add(s4);
        //遍历集合(增强for)
        for (Student s : hs) {
            System.out.println(s.getName() + "," + s.getAge());
        }
    }
}HashSet集合存储自定义类型元素,要想实现元素的唯一,要求必须重写hashCode方法和equals方法
 
                    
                     
                    
                 
                    
                
 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号