比较对象有两种方式:一是在对象类中实现Comparable接口重写compareTo()方法;二是定义一个专门用于对象比较的比较器,实现这个比较器的方法是实现Comparator接口并重写compare()方法。其中Comparable接口提供的比较方法称为自然顺序,例如字母按照字典顺序,数值按照数值大小顺序。
无论是哪种方式,每个待插入的元素都需要先转型为Comparable,确定了将要存储在二叉树上的节点位置后,然后再转型为Object存储到集合中。
插入String类对象。
由于String已经重写了compareTo(),因此下面插入String对象到TreeSet集合中没有任何问题。
但不能将上面"t.add(23)"等取消注释,虽然Integer类也重写了compareTo(),但在插入这些Integer类元素时,集合中已经存在String类的元素,String类的compareTo()和Integer的compareTo()的比较方法不一样,使得这两类元素之间无法比较大小,也就无法决定数值类的元素插入到二叉树的哪个节点。
插入实现了Comparable接口且重写了compareTo()的自定义对象。
例如Student对象,如果没有重写compareTo()方法,将抛出异常,提示无法转型为Comparable。
结果:
Exception in thread "main" java.lang.ClassCastException: Student cannot be cast to java.lang.Comparable at java.util.TreeMap.compare(Unknown Source) at java.util.TreeMap.put(Unknown Source) at java.util.TreeSet.add(Unknown Source) at TestTreeSet.main(TestTreeSet.java:8)所以,修改Student重写compareTo(),在重写应该考虑哪个作为主排序属性,哪个作为次要排序属性。例如以name为主排序属性,age为次排序属性。compareTo()返回正数则表示大于,返回负数则表示小于,返回0则表示等于。如下:
class Student implements Comparable { String name; int age; Student(String name,int n) { this.name = name; this.age = n; } public String toString() { return this.name + " " + this.age; } public int compareTo(Object obj) { if (!(obj instanceof Student)) { throw new ClassCastException("Class cast wrong!"); } Student stu = (Student)obj; // compare name first, then age int temp = this.name.compareTo(stu.name); return temp == 0 ? this.age - stu.age :temp; } }于是插入Student时,将根据name中的字母顺序,相同时再根据age大小顺序,最后如果都相同,则认为元素重复,不应该插入到集合中。
t.add(new Student("Malongshuai1",23)); t.add(new Student("Malongshuai3",21)); t.add(new Student("Malongshuai2",23)); t.add(new Student("Malongshuai1",23)); //重复 t.add(new Student("Malongshuai1",22));结果:
Malongshuai1 22 Malongshuai1 23 Malongshuai2 23 Malongshuai3 21