一:TreeSet的特点
- 唯一(set集合的通用特点)/元素不可重复
- 无序的部分:不按照输入数据时候的顺序输出
- 有序的部分:会按照升序来帮你输出
二:TreeSet集合中导入数据以及输出
1.integer类型的数据
public static void main(String[] args) {
TreeSet<Integer> set1 = new TreeSet<>();
set1.add(8);
set1.add(4);
set1.add(3);
set1.add(5);
System.out.println(set1);//输出为:[3, 4, 5, 8]
}
2.String类型的数据
public static void main(String[] args) {
TreeSet<String> set1 = new TreeSet<>();
set1.add("eqweqwe");
set1.add("caewae");
set1.add("qwads");
set1.add("aasd");
System.out.println(set1);//输出为:[aasd, caewae, eqweqwe, qwads]
}
由此可见,对于Integer类型和String类型输出以后,都是会将其自动排序,按照升序的翻方式来将其输出,而且整型是对其数值的大小比较,字符串类型则是按照首字母的以及往后字母的大小来比较
其原理是由于Integer类中包含了重写Comparable接口的compareTo方法而String也是因为如此,才能够正常的排序输出
那么如果往TreeSet集合中存入自定义的引用类型又会如何呢?
3.自定义引用类型的集合
在这边,先创建一个学生类
public class Student implements Comparable<Student>{
private int age;
private String name;
private double height;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getHeight() {
return height;
}
public void setHeight(double height) {
this.height = height;
}
public Student() {
}
public Student(int age, String name, double height) {
this.age = age;
this.name = name;
this.height = height;
}
@Override
public String toString() {
return "Student{" +
"age=" + age +
", name='" + name + '\'' +
", height=" + height +
**加粗样式** '}';
}
@Override
public int compareTo(Student o) {
return this.getAge()-o.getAge();
}
}
可以看出,此类中定义了:
年龄(int age),身高(double height),姓名(String name)三个私有属性
接着:
- 将此类实现comparable接口,所以必须将其compareTo方法重写
- 并将其泛型险限制为Student,这时候往此方法中传入的形参就必须是student类型了**
最后具体重写方法:(称之为内部比较器)
- 如果要比较年龄,则返回的是 this.getAge()-o.getAge();并且返回的类型为int型
- 如果要比较身高,则不能直接两者相减,即return this.getHeight()-o.getHeight(),因为身高在这里定义的是double型,所以返回的会是double型,而不是重写比较方法后要求的int型
这时候可以将两者封装为对象,将其装箱成为Double类
这时候只要return ((Double)this.getHeight).compareTo((Double)o.getHeight)
调用的是Double类里面已经重写过的比较方法,非常方便
4.自定义类型对TreeSet的输入与输出
这时候整个自定义类就完成了,TreeSet集合可以正常的输入这个类的数据,并且可以正常升序输出元素了,至于按照三个私有属性,按照哪个属性来升序输出,只需要在比较器里比较哪个属性即可
例如:我Student类中内部比较器里面,比较的是age属性,并且返回的是
this.getAge()-o.getAge,
那么我此刻往TreeSet中添加学生类
TreeSet<Student> set1 = new TreeSet<>();
set1.add(new Student(17,"zhangsan",98.8));
set1.add(new Student(15,"wangwu",96.7));
那么我这时候输出的会是,对年龄进行排序后的结果,且为升序顺序
那么因为王五的年龄比张三小,则一定会第一个输出,结果为:
[Student{age=15, name=‘wangwu’, height=96.7}, Student{age=17, name=‘zhangsan’, height=98.8}]
值得注意的是,因为我们要比较的是年龄属性,则如果年龄属性重复的话,因为TreeSet集合的唯一性原则,则只会输出一个,而不会全部输出
例如:
TreeSet<Student> set1 = new TreeSet<>();
set1.add(new Student(17,"zhangsan",98.8));
set1.add(new Student(17,"wangwu",96.7));
这时候只会输出张三
而如果年龄不同,名字相同,身高相同也是可以正常输出的,因为我们比较的只是身高
TreeSet<Student> set1 = new TreeSet<>();
set1.add(new Student(17,"zhangsan",98.8));
set1.add(new Student(15,"zhangsan",98.8));
这样的话依旧是会正常输出两个元素
以上讲的是内部比较器,而且TreeSet集合默认使用的是内部比较器,如果此时我们没定义内部比较器,则TreeSet搜索不到内部比较器,则被判定为无法正常输出,则会报错,这时候我们就需要定义一个外部比较器
新建一个外部比较器类,并且命名为MyCompare
public class MyCompare01 implements Comparator<Student>{
@Override
public int compare(Student o1, Student o2) {
return ((Double)o1.getHeight()).compareTo((Double) o2.getHeight());
}
}
此类实现的是Comparator接口,并且泛型定义的也是student,重写其compare方法后,这个外部比较器就构建完成了!!!!!!!
现在问题是,TreeSet只能感知到内部比较器,因此外部比较器需要声明一下才能正常使用
- 新建一个比较器对象
main
Comparator<Stuent> com=new MyCompare();
TreeSet<Student ts=new TreeSet<>(com)
这时候即可正常使用外部构造器,并且正常输入输出
2.或者不用新建一个类作为外部比较器也可以,因为有匿名内部类
main{
Comparator<Student> mycomparator =new Comparator<Student>(){
@override
pubulic int compare(Student o1,Student o2){
return o1.getAge-o2.getAge;
}
}
}