TreeSet类集的排序杂谈

Posted by pcm5566 on October 23, 2018

第二篇博客

关于java类集TreeSet的杂谈

既然TreeSet本身是可以排序的,那么它是怎么实现排序的呢?

class Person{
    private String name;
    private int age;
    public Person (String name,int age){
        this.name=name;
        this.age=age;
    }
    public String toString(){
        return "姓名:"+this.name+",年龄:"+this.age;
    }
}
public class TreeSetDemo {
    public static void main(String[] args) {
        Set<Person> allset = new TreeSet<Person>();
        allset.add(new Person("张三",30));
        allset.add(new Person("李四",31));
        allset.add(new Person("王五",32));
        allset.add(new Person("王五",32));
        allset.add(new Person("王五",32));
        allset.add(new Person("赵六",33));
        allset.add(new Person("孙七",33));
        System.out.println(allset);
    }
}

运行时出现以下错误:

Exception in thread "main" java.lang.ClassCastException: changmin.blog.Person cannot be cast to java.lang.Comparable
	at java.util.TreeMap.compare(TreeMap.java:1294)
	at java.util.TreeMap.put(TreeMap.java:538)
	at java.util.TreeSet.add(TreeSet.java:255)
	at changmin.blog.TreeSetDemo.main(TreeSetDemo.java:24)

以上程序代码出现了ClassCastException异常,是因为TreeSet中的元素是有序存放,所以对于一个对象必须指定好排序规则,且TreeSet中的每个对象所在的类都必须实现Comparable接口才可以正常使用。

下面我们对Person类指定排序规则

class Person implements Comparable<Person>{
    private String name;
    private int age;
    public Person (String name,int age){
        this.name=name;
        this.age=age;
    }
    public String toString(){
        return "姓名:"+this.name+",年龄:"+this.age;
    }
    public int compareTo(Person per){
        if (this.age>per.age){
            return 1;
        }else if (this.age<per.age){
            return -1;
        }else {
            return 0;
        }
    }
}

指定排序规则后运行结果如下:

[姓名:张三,年龄:30, 姓名:李四,年龄:31, 姓名:王五,年龄:32, 姓名:赵六,年龄:33]

从结果中来看,重复的“王五”对象只有一个了;“赵六”和“孙七”的数据中姓名不重复,只是年龄重复了,但是“孙七”却没有加入到集合中。这是由于采用了比较器造成的,因为比较器操作时如果某个属性没有进行比较的指定,则也会认为是同一个对象,所以此时应该在Person类的compareTo方法中增加按姓名比较。

return this.name.compareTo(per.name)

[姓名:张三,年龄:30, 姓名:李四,年龄:31, 姓名:王五,年龄:32, 姓名:孙七,年龄:33, 姓名:赵六,年龄:33] 增加了“孙七”,同时也没有重复内容,但此时的重复内容的去掉并不是真正意义上的去掉重复元素。因为此时靠的是Comparable完成,如果换成HashSet则也会出现重复的内容。