Java集合框架总结(3)——TreeSet类的排序问题
TreeSet支持两种排序方法:自然排序和定制排序。TreeSet默认采用自然排序。
1、自然排序
TreeSet会调用集合元素的compareTo(Object obj)方法来比较元素之间大小关系,然后将集合元素按升序排列,这种方式就是自然排序。(比较的前提:两个对象的类型相同)。
java提供了一个Comparable接口,该接口里定义了一个compareTo(Object obj)方法,该方法返回一个整数值,实现该接口的类必须实现该方法,实现了该接口的类的对象就可以比较大小。当一个对象调用该方法与另一个对象进行比较,例如obj1.comparTo(obj2),如果该方法返回0,则表明这两个对象相等;如果返回一个正整数,则表明obj1大于obj2;如果该方法返回一个负整数,则表明obj1小于obj2.
java常用类实现Comparable接口,并提供了比较大小的标准。实现Comparable接口的常用类:
如果试图把一个对象添加进TreeSet时,则该对象的类必须实现Comparable接口。
如下程序则会报错:
< }="" r(5)));="" hs.contains(new="" +="" system.out.println(?hs是否包含count为5的r对象??="" 输出false="" r(-3)));="" system.out.println(?hs是否包含count为-3的r对象??="" system.out.println(hs);="" r(-3));="" hs.remove(new="" 再次输出count将看到treeset里的元素处于无序状态="" first.count="-3;" 为第一个元素的count属性赋值="" first="(R)it.next();" r="" it="hs.iterator();" iterator="" 取出第一个元素="" 打印treeset集合,集合元素是有序排列的="" r(-2));="" hs.add(new="" r(9));="" r(5));="" hashset();="" hs="new" hashset="" {="" args)="" main(string[]="" void="" static="" public="" testhashset2="" this.count;="" return="" hashcode()="" int="" false;="" true;="" this.count)="" (r.count="=" if="" r="(R)obj;" r)="" instanceof="" (obj="" obj)="" equals(object="" boolean="" count="" name="code">程序运行结果:
[R(count属性:-3), R(count属性:-2), R(count属性:5), R(count属性:9)]?
[R(count属性:20), R(count属性:-2), R(count属性:5), R(count属性:-2)]?
[R(count属性:20), R(count属性:-2), R(count属性:5), R(count属性:-2)]?
[R(count属性:20), R(count属性:-2), R(count属性:-2)]
说明:
上面程序中的R对象是一个正常重写了equals方法和comparable方法类,这两个方法都以R对象的count属性作为判断的依据。可以看到程序第一次输出的结果是有序排列的。当改变R对象的count属性,程序的输出结果也发生了改变,而且包含了重复元素。一旦改变了TreeSet集合里可变元素的属性,当再视图删除该对象时,TreeSet也会删除失败(甚至集合中原有的、属性没被修改,但与修改后元素相等的元素也无法删除),所以删除count
为-2的R对象时,没有任何元素被删除;程序可以删除count为5的R对象,这表明TreeSet可以删除没有被修改属性、且不与其他被修改属性的对象重复的对象。
总结:与HashSet在处理这些对象时将非常复杂,而且容易出错。为了让程序更具健壮,推荐HashSet和TreeSet集合中只放入不可变对象。
2、定制排序
TreeSet的自然排序是根据集合元素的大小,TreeSet将他们以升序排列。如果需要实现定制排序,例如降序,则可以使用Comparator接口。该接口里包含一个int compare(T o1, T o2)方法,该方法用于比较o1和o2的大小。
如果需要实现定制排序,则需要在创建TreeSet集合对象时,并提供一个Comparator对象与该TreeSet集合关联,由该Comparator对象负责集合元素的排序逻辑。
如下程序所示:
< }="" +="" {="" args)="" main(string[]="" void="" static="" public="" return="" int="" if="" name="code" system.out.println(ts);="" m(9));="" ts.add(new="" m(-3));="" m(5));="" });="" 1;="" else="" 0;="" m2.age)="" (m1.age="" -1;="" >="" o2;="" m2="(M)" m="" o1;="" m1="(M)" o2)="" object="" o1,="" compare(object="" comparator()="" treeset(new="" ts="new" treeset="" testtreeset3="" }public="" age="">程序运行结果:
[M对象(age:9), M对象(age:5), M对象(age:-3)]
说明:
上面程序中创建了一个Comparator接口的匿名内部类对象,该对象负责ts集合的排序。所以当我们把M对象添加到ts集合中时,无须M类实现Comparable接口,因为此时TreeSet无须通过M对象来比较大小,而是由与TreeSet关联的Comparator对象来负责集合元素的排序。使用定制排序时,TreeSet对集合元素排序时不管集合元素本身的大小,而是由Comparator对象负责集合元素的排序规则。
联系客服