在上一篇文章中,我们介绍了Set接口以及它的实现类HashSet容器类,关于Set接口的实现类,我们说它有两个常用的实现类,分别是HashSet和TreeSet。那么同为Set接口的实现类,TreeSet容器类和HashSet容器类有什么区别呢?
作为Set接口的实现类,TreeSet容器类和HashSet容器类最打的区别就是TreeSet容器类支持元素的排序操作。它的底层是通过TreeMap来实现的,等价于一个简化版的TreeSet。在TreeSet容器类中,通过key来存储Set的元素。因为TreeSet容器类支持对元素进行排序操纵,因此在创建TreeSet容器类的对象时我们要给定容器排序的规则,这里的排序规则一般有两种方式,一种是通过元素自身实现排序规则,另一种是创建比较器来实现排序规则。
在谈排序规则之前我们先简单说一下TreeSet容器类的使用,由于它是Set接口的实现类,因此可以用Set接口来实例化TreeSet容器类对象。由于Set接口是泛型接口,因此在实例化的时候要给定泛型类,同时采用泛型类的实例化格式创建TreeSet容器类对象。
由于TreeSet是Set接口的具体实现类,因此TreeSet容器中的元素也具有Set接口定义的容器中的特征,即不可重复,当我们在容器中添加了相同元素的时候,后一个元素会把前一个元素覆盖掉。也就是在这里要注意,TreeSet容器类中提供了元素的排序操作,因此此容器中的元素可以理解为是有序的,但是由于其排序操作和数组中的自动有序是不同的,因此我们仍旧不可以通过循环结构来对其元素进行遍历,只能通过迭代器来对其中的元素来进行遍历。
接下来我们重点解决TreerSet容器类中的排序问题,我们以下的演示代码来说明。首先说的是通过元素自身来实现排序的操作。由于在String类中实现了Compare接口中的compareTo方法,因此在我们往TreeSet容器中添加字符串元素的时候,它会调用compareTo方法来实现排序,比如我们在TreeSet容器set添加字符串元素“我”“你”“和”“他”,这时我们遍历元素,打印结果为“他”“你”“和”“我”,已经进行了排序处理。这样说的话,当我们将自定义的类作为TreeSet容器类中的元素存储时,要通过元素自身实现排序操作,只需要在这个类中重写compareTo方法即可。比如在我们使用之前的User类为例,在User类中,我们添加了几行代码重写了compareTo方法,在这里我们定义的排序规则为this.usersAge > o.usersAge,实现的是按照年龄由小到大排序。这时根据运行结果,我们发现,以User类作为元素的容器set1已经按照年龄的进行排序了,此时如果遇到年龄相同的情况,则会默认按照另一个属性来排序,比如这里,元素“他”和“你”的年龄都是20,这时便按照userName这个实现了compareTo方法的属性来进行排序。这就是在元素中重写compareTo方法来实现的通过元素自身实现的排序规则。
那么如何实现通过创建比较器来进行排序操作呢?这个根据字面理解,也就是要我们在类之外创建一个比较器来实现两个元素只见的大小比较,然后根据比较的结果来进行排序。这里我们以一个Student类来说明。在Student类中,定义了属性name和age,并提供了相应的set和get方法以及构造器。简单来说就是一个普通类。定义完这个类,我们在这个类的外部重新定义个类StudentComparator,这个类就是比较器,在这个类中我们定义比较规则,在年龄不同时依据年龄按从小到大进行排序,年龄相同时按照name来排序,由于name属性是String类,这个类中已经实现了compareTo方法,因此我们只需要调用compareTo方法就能完成排序操作了。定义完比较器,回到演示代码TreeSetTest类中,当我们创建set2容器时,在创建对象的结尾new TreeSet<>();的括号中,可以发现,系统允许我们传入参数,这个参数就是比较器,这时将我们建好的比较器传入,代码后半段变成了new TreeSet<>(new StudentComparator());。然后我们照旧添加元素,遍历后能发现其结果已经按照我们在比较器中定义的规则进行排序了。这就是通过比较器来实现排序操作的方法。
package com.container.demo;
import java.util.Objects;
public class User implements Comparable<User>{
private String usersName;
private int usersAge;
public String getUsersName() {
return usersName;
}
public void setUsersName(String usersName) {
this.usersName = usersName;
}
public int getUsersAge() {
return usersAge;
}
public void setUsersAge(int usersAge) {
this.usersAge = usersAge;
}
@Override
public String toString() {
return "User{" +
"usersName='" + usersName + '\'' +
", usersAge=" + usersAge +
'}';
}
public User(String usersName, int usersAge) {
this.usersName = usersName;
this.usersAge = usersAge;
}
public User() {
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
User user = (User) o;
return usersAge == user.usersAge && Objects.equals(usersName, user.usersName);
}
@Override
public int hashCode() {
return Objects.hash(usersName, usersAge);
}
//定义比较规则
//正数:大,负数:小,0:相等
@Override
public int compareTo(User o) {
if(this.usersAge > o.usersAge)
return 1;
if(this.usersAge == o.usersAge){
return this.usersName.compareTo(o.getUsersName());
}
return -1;
}
}
package com.container.demo;
import java.util.Objects;
public class Student {
private String name;
private int age;
@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);
}
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;
}
public Student() {
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
package com.container.demo;
//比较器
import java.util.Comparator;
public class StudentComparator implements Comparator<Student> {
//定义比较规则
@Override
public int compare(Student o1, Student o2) {
if(o1.getAge() >o2.getAge()){
return 1;
}
if(o1.getAge() == o2.getAge()){
return o1.getName().compareTo(o2.getName());
}
return -1;
}
}
package com.container.demo;
import java.util.Set;
import java.util.TreeSet;
public class TreeSetTest {
public static void main(String[] args) {
//实例化TreeSet
Set<String> set = new TreeSet<>();
//添加元素
set.add("我");
set.add("你");
set.add("和");
set.add("他");
//获取元素
for (String sets :set
) {
System.out.println(sets);
}
System.out.println("________________________");
Set<User> set1 = new TreeSet<>();
User u = new User("我",18);
User u1 = new User("你",20);
User u2 = new User("他",20);
set1.add(u);
set1.add(u1);
set1.add(u2);
for (User ob:set1
) {
System.out.println(ob);
}
System.out.println("_____________________");
Set<Student> set2 = new TreeSet<>(new StudentComparator());
Student s = new Student("linling",20);
Student s1 = new Student("linyi",25);
Student s2 = new Student("liner",18);
Student s3 = new Student("linsan",18);
set2.add(s);
set2.add(s1);
set2.add(s2);
set2.add(s3);
for (Student stu:set2
) {
System.out.println(stu);
}
}
}