集合(16):set接口的子类----TreeSet类
1、TreeSet类的概述
元素唯一,元素的顺序可以按照某种规则进行排序
两种排序方式:
自然排序
比较器排序
2、TreeSet类的使用案例1
import java.util.TreeSet;
public class TreeSetDemo1 {
public static void main(String[] args) {
//创建一个集合对象
TreeSet<Integer> ts = new TreeSet<>();
//添加元素到集合中
ts.add(20);
ts.add(18);
ts.add(23);
ts.add(24);
ts.add(66);
ts.add(12);
ts.add(18);
ts.add(20);
ts.add(23);
ts.add(2);
//遍历
for(Integer i : ts){
System.out.println(i);
}
}
}
执行结果如下:
2
12
18
20
23
24
66
Process finished with exit code 0
//通过结果发现,TreeSet不仅去重,而且还重新排序了
3、查看源码,分析TreeSet为什么不仅去重,而且还重新排序
4、TreeSet类的使用案例2:TreeSet存储学生对象并遍历
第1步:需要定义一个学生类
第2步:
import java.util.TreeSet;
public class TreeSetDemo2 {
public static void main(String[] args) {
//创建集合对象
TreeSet<Student3> ts = new TreeSet<>();
//创建学生对象
Student3 s1 = new Student3("周姐",24);
Student3 s2 = new Student3("李元浩",25);
Student3 s3 = new Student3("李湘赫",22);
Student3 s4 = new Student3("汉子哥",26);
Student3 s5 = new Student3("硬币哥",21);
Student3 s6 = new Student3("乌兹",20);
Student3 s7 = new Student3("李元浩",25);
Student3 s8 = new Student3("厂长",25);
//将学生对象插入到集合中
ts.add(s1);
ts.add(s2);
ts.add(s3);
ts.add(s4);
ts.add(s5);
ts.add(s6);
ts.add(s7);
ts.add(s8);
for (Student3 s:ts){
System.out.println(s);
}
}
}
//运行的时候报错
按照正常的写法,我们一运行就报错了
java.lang.ClassCastException:类型转换异常
通过源码可知,创建TreeSet对象调用的是无参构造方法,
走的是自然排序,而底层源码有一步向下转型
Comparable<? super K> k = (Comparable<? super K>) key;
报错的原因是我们Student3类没有实现Comparable接口,无法向下转型
回到第1步我们定义的学生类中来修改
//定义学生类的时候需要实现Comparable接口
//改进1处:
public class Student3 implements Comparable<Student3> {
private String name;
private int age;
public Student3() {
}
...(此处省略)..
改进1后,还是会报错,是因为实现接口需要重写借口的所有方法,
我们少重写了接口中的comparableTo方法,需要添加进去
//改进2处:
public class Student3 implements Comparable<Student3> {
private String name;
private int age;
public Student3() {
}
...(此处省略)..
@Override
public String toString() {
return "Student2{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
//重写compareTo方法
@Override
public int compareTo(Student3 o) {
return 0;
}
在改进2处虽然重写了compareTo方法,但是在运行程序的时候,只打印了第一个对象
Student2{name='周姐', age=24}
Process finished with exit code 0
很显然,问题出在了返回值return 0;
如果return 1;打印结果如下:
Student2{name='周姐', age=24}
Student2{name='李元浩', age=25}
Student2{name='李湘赫', age=22}
Student2{name='汉子哥', age=26}
Student2{name='硬币哥', age=21}
Student2{name='乌兹', age=20}
Student2{name='李元浩', age=25}
Student2{name='厂长', age=25}
Process finished with exit code 0//return 1;没有去重
如果return -1;打印结果如下:
Student2{name='厂长', age=25}
Student2{name='李元浩', age=25}
Student2{name='乌兹', age=20}
Student2{name='硬币哥', age=21}
Student2{name='汉子哥', age=26}
Student2{name='李湘赫', age=22}
Student2{name='李元浩', age=25}
Student2{name='周姐', age=24}
Process finished with exit code 0//return 1;顺序全部颠倒
由此可知,返回值return 0; return 1; return -1;都不符合
需求:我想在去重的前提下,按照年龄进行排序,返回值为 return this.age - o.age;
输出结果如下:
Student2{name='乌兹', age=20}
Student2{name='硬币哥', age=21}
Student2{name='李湘赫', age=22}
Student2{name='周姐', age=24}
Student2{name='李元浩', age=25}
Student2{name='汉子哥', age=26}
Process finished with exit code 0
//年龄进行了排序,但是却把年龄相同的给去除了,不符合
最终的修改
@Override
public int compareTo(Student3 o) {
//年龄一样,姓名不一定一样
//主要条件(题目要求的条件)
int i = this.age - o.age;
//隐含条件(需要自己挖掘)
int i2 = i == 0 ? this.name.compareTo(o.name) : i;
return i2;
}
}
最终的运行结果:
Student2{name='乌兹', age=20}
Student2{name='硬币哥', age=21}
Student2{name='李湘赫', age=22}
Student2{name='周姐', age=24}
Student2{name='厂长', age=25}
Student2{name='李元浩', age=25}
Student2{name='汉子哥', age=26}
Process finished with exit code 0