上篇博客中,我们已经了解到TreeSet为有序集合,按照Comparator接口定义的排序顺序进行排序。一些基础类型,都已经实现了该接口,默认是按照自然排序进行排列。而我们自定义类型需要手动实现接口。
测试
首先我们来做一个测试。测试TreeSet的排序功能。
用例一:
在集合中添加了四个元素
输出结果是:ABCD
用例二:
颠倒顺序
输出结果是:ABCD
所以TreeSet的默认顺序并不是按照装入集合的先后排序的。而是按照字符的顺序。
用例三:
添加实体类
输出报错。我们跟踪源代码发现,当set进行添加时,Set.add(s2),会调用TreeMap方法
public TreeMap(Map<? extends K, ? extends V> m) {
comparator = null;
putAll(m);
}
其中putAll中调用compare方法,compare方法如下:
final int compare(Object k1, Object k2) {
return comparator==null ? ((Comparable<? super K>)k1).compareTo((K)k2)
: comparator.compare((K)k1, (K)k2);
}
其中,compareTo在不明确排序类型标准时,无法进行比较。因此会报错:Student cannot be cast to java.lang.Comparable
通过以上看出,①如果想要对TreeSet实现指定的排序,需要自定义排序顺序。或是②如果TreeSet操作自定义类,也需要自定义排序顺序。
具体实现:
目标,TreeSet中存放学生实体,并能通过年龄进行排序。
上面博客中,我们提到了TreeSet的类构造函数,如果自定义排序,则一定需要
public TreeSet(Comparator<? super E> comparator) {
this(new TreeMap<>(comparator));
}
需要传递Comparator接口这样一个实例,所以需要自己去定义Comparator的一个实现类。 然后实现该接口中compare 方法。
如下:
学生类:
public class Student {
int age;
public Student(int age){
this.age=age;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
Comparator实现类:
class StudentComparator implements Comparator{
@Override
public int compare(Object o1, Object o2) {
Student s1=(Student)o1;
Student s2=(Student)o2;
//按照升序排列
return s1.age-s2.age;
}
}
调用:
TreeSet set=new TreeSet(new StudentComparator());
具体过程:
public static void main(String[] args){
TreeSet set=new TreeSet(new StudentComparator());
Student s1=new Student(13);
Student s2=new Student(10);
Student s3=new Student(11);
Student s4=new Student(12);
set.add(s1);
set.add(s2);
set.add(s3);
set.add(s4);
for (Iterator iterator = set.iterator(); iterator.hasNext();) {
Student object = (Student) iterator.next();
System.out.print(object.getAge()+" 、");
}
结果按照年龄进行了排序:
PS:实际上这里通过Comparator也是应用了策略模式~
总结:
TreeSet自定义排序需要实现Comparator接口,并将该类型示例传入TreeSet初始化的参数中。在Comparator实现中写排序的方式和规则。,