首先TreeSet底层构造器实际是TreeMap(有key.value为null);
TreeMap的底层是红黑树(二叉树);
这里并没有分析底层,只是说明我的一些问题。
一.前置技能
- 排序分为自然排序和定制排序。自然排序(按元素值大小)需该对象所属类实现comparable<T>接口,定制排序自定义比较器实现comparator<T>接口。
- TreeSet/TreeMap的排序需要排序对象依赖comparable<T>接口和comparator<T>接口,基本数据包装类已经实现了这些接口,可以直接进行排序(自然排序)。而自定义对象需实现这些接口(无论是自然排序还是定制排序)。
- 自定义类实现comparable<T>接口 需重写 public int compareTo(T t){}方法;
public int compareTo(Person o) { // TODO Auto-generated method stub System.out.println(this+"父类比较方法"+o); int tmp=this.age-o.age; return tmp==0?this.name.compareTo(o.name):tmp; }
- 实现comparator<T>接口需要新建比较器实现该接口并重写public int compare(T t1, T t2) {}方法。然后调用TreeSet的构造器:TreeSet(Comparator<? super E>c)来完成定制排序.
public class ComparatoByName implements Comparator<Person> { /* * 定制排序比较器 * 可以接受父类及其子类 */ public int compare(Person o1, Person o2) { // TODO Auto-generated method stub int tmp=o1.getName().compareTo(o2.getName()); return tmp==0?o1.getAge()-o2.getAge():tmp; } } TreeSet<Person> ts=new TreeSet<Person>(new ComparatoByName()); //子类也可以 原因是TreeSet(Comparator<? super E>c) TreeSet<Student> ts=new TreeSet<Student>(new ComparatoByName());
二.拓展。
1.对于自然排序实现comparatable<T>接口的类来说,他的子类为泛型的集合依然可以借用父类的comparaTo方法实现自然排序。因为父类实现接口重写方法后 子类可以继承到这个方法。当然也可以自己重写该方法,新的排序规则。
Q:Java_TreeSet里面放对象,如果同时放入了父类和子类的实例对象,那比较时使用的是父类的compareTo方法,还是使用的子类的compareTo方法,还是抛异常?
P:所以在TreeSet/TreeMap中,添加对象为父类就调用父类的compareTo方法,子类调用子类的compareTo方法。
2.对于定制排序的比较器类实现的comparator<T> 也可以接受子类类型的集合来调用该比较器实现排序,是因为
因为比较器的实现的接口为Comparator<? super E> 这里的对象? 可以是E或E的父类:比如上面的代码中比较器实现的接口为Person类为父类(就是“?”)而TreeSet确实Student类子类依然可以排序成功。
3.对于工具类Collections也内置了一个静态方法Collections.sort();他的参数类型是
public static <T extends Comparable<? super T>> void sort(List<T> list) {
Collections.sort(list);
}
这里的泛型解释:这里的T类型必须实现Comparable<>接口并且可以是这个Comparable<>泛型约束的子类,使该方法在针对自定义类型时更加灵活。更多解释在https://www.cnblogs.com/xiaomiganfan/p/5390252.html。