walterwing  
日历
<2008年7月>
293012345
6789101112
13141516171819
20212223242526
272829303112
3456789
统计
  • 随笔 - 12
  • 文章 - 1
  • 评论 - 7
  • 引用 - 0

导航

常用链接

留言簿(1)

随笔分类

随笔档案

搜索

  •  

最新评论

阅读排行榜

评论排行榜

 
前面介绍完了几个Collections Framework的几个主要接口,下面来讲一下对象是如何排序的,为下面的SortedSet和SortedMap做准备。

举个例子,我们有个list,里面存储了若干个String,那么我们可以用下面的方法来对list内部的String按照字母顺序来排序:

Collections.sort(list);

那如果list里存放的不是String,而是其他类型的对象呢?能否排序就取决于该对象是否实现了Comparable这个接口,如果没有的话,Collections.sort()方法就将抛出ClassCastExcepton。

下面的表格列出了java里实现了Comparable接口的一些重要的类:

Classes Implementing Comparable
Class Natural Ordering
Byte Signed numerical
Character Unsigned numerical
Long Signed numerical
Integer Signed numerical
Short Signed numerical
Double Signed numerical
Float Signed numerical
BigInteger Signed numerical
BigDecimal Signed numerical
Boolean Boolean.FALSE < Boolean.TRUE
File System-dependent lexicographic on path name
String Lexicographic
Date Chronological
CollationKey Locale-specific lexicographic

如果你想对自己的类实现Comparable接口,一定要先参考API文档关于Comparable接口的说明。

另外,如果你想用自己的排序屏蔽原本的排序方式,又或者你想对某个类的对象排序,但该类并没有实现Comparable接口,这个时候,你就可以用Comparator接口来实现你自己的排序方式。

但有一点要注意,排序也不是乱排的,应该尽量和类方法中的equals方法保持一致,尤其是当Comparator用在SortedSet或者SortedMap中的时候(这两个可以通过指定Comparator来覆盖自然排序方式)。

举个例子来说:

public class Cmp {

    
/**
     * 
@param args
     
*/
    
public static void main(String[] args) {
        SortedSet set 
= new TreeSet();
        set.add(
"a");
        set.add(
"a");
        
        Iterator it 
= set.iterator();
        
while(it.hasNext()) {
            System.out.println(it.next());
        }
        
    }

}

我们知道Set是不允许有重复元素的,所以即使我们加入了两个“a”,最后输出的结果仍然是只有一个“a”。

但如果我们对程序做如下修改,指定自己的Comparator:
public class Cmp {
    
    
static final Comparator cp = new Comparator() {
        
public int compare(Object o1, Object o2) {
            
return 1;
        }
    };

    
/**
     * 
@param args
     
*/
    
public static void main(String[] args) {
        SortedSet set 
= new TreeSet(cp);
        set.add(
"a");
        set.add(
"a");
        
        Iterator it 
= set.iterator();
        
while(it.hasNext()) {
            System.out.println(it.next());
        }
        
    }

}

这次输出的结果将是两个"a",这与Set本身的规范并不相符。



6. SortedSet

SortedSet一种按升序来排列元素的Set。排序的规则是按照元素的自然顺序,或是按照构造函数中指定的Comparator规定的顺序。

下面是SortedSet的定义:

public interface SortedSet<E> extends Set<E> {
    
// Range-view
    SortedSet<E> subSet(E fromElement, E toElement);
    SortedSet
<E> headSet(E toElement);
    SortedSet
<E> tailSet(E fromElement);

    
// Endpoints
    E first();
    E last();

    
// Comparator access
    Comparator<? super E> comparator();
}

我们看到,SortedSet提供了一些特殊的操作:

  • Range view — allows arbitrary range operations on the sorted set
  • Endpoints — returns the first or last element in the sorted set
  • Comparator access — returns the Comparator, if any, used to sort the set
至于其他的从Set继承过来的操作,基本都和Set一样。之所以说“基本”,是因为有两个例外:

·SortedSet得到的iterator是按顺序进行遍历的(Set没有顺序)
·toArray得到的数组是按序排列SortedSet中的元素的(Set没有顺序)

SortedSet (Java 2 Platform SE 6)

所有通用有序 set 实现类都应该提供 4 个“标准”构造方法:

1) void(无参数)构造方法,它创建一个空的有序 set,按照元素的自然顺序进行排序。

2) 带有一个 Comparator 类型参数的构造方法,它创建一个空的有序 set,根据指定的比较器进行排序。

3) 带有一个 Collection 类型参数的构造方法,它创建一个新的有序 set,其元素与参数相同,按照元素的自然顺序进行排序。

4) 带有一个 SortedSet 类型参数的构造方法,它创建一个新的有序 set,其元素和排序方法与输入的有序 set 相同。如何做到这一点?别忘了SortedSet本身就有一个comparator()方法,可以返回他所用的Comparator。但要注意的是无法保证强制实施此建议,因为接口不能包含构造方法。


在介绍List的时候,我们曾经强调,List里的range-view方法List<E> subList(int from, int to);是要严格避免滥用的。因为在subList的作用域范围内,任何对list本身的修改都将使subList的行为不可预期。

但是在SortedSet里情况就不一样了,你应该注意到,SortedSet里的三个range-view方法,都是根据提供的比较范围来截取subSet,而不是像List里那样使用索引。这样在subSet的作用域范围内,对set本身的修改都将反映到subSet上,反之亦然。参见下面的例子:


public class Cmp {

    
/**
     * 
@param args
     
*/
    
public static void main(String[] args) {
//        SortedSet set = new TreeSet(cp);
        SortedSet set = new TreeSet();
        set.add(
"a");
        set.add(
"b");
        set.add(
"c");
        set.add(
"d");
        set.add(
"e");
        
        SortedSet sub 
= set.tailSet("c");
        
        Iterator it 
= sub.iterator();
        
while(it.hasNext()) {
            System.out.println(it.next());
        }
        
        set.add(
"f");
        
        System.out.println(
"-------------------");
        
        it 
= sub.iterator();
        
while(it.hasNext()) {
            System.out.println(it.next());
        }
        
    }

}

输出的结果是:

c
d
e
-------------------
c
d
e
f

可以看到,我们得到“值大于等于c”的subSet后,当我们再向原来的set加入一个新的元素“f”,由于这个元素也大于“c”,那么这个元素也将反映到subSet上。


下面介绍一个比较特殊的小技巧:通过使用subSet,如何得到一个闭包的结果?
我们知道,如果按照一般的调用,下面的代码是获得大于等于“doorbell”而小于“pickle”的subSet:

dictionary.subSet("doorbell""pickle");

而我们可以通过下面方法得到大于等于“doorbell”而小于等于“pickle”的subSet:

dictionary.subSet("doorbell""pickle\0");

同理,我们可以通过下面方法得到大于“doorbell”而小于“pickle”的subSet:

dictionary.subSet("doorbell\0""pickle");


7. SortedMap

SortedMap是对key进行升序排列的Map。

下面是其定义:

public interface SortedMap<K, V> extends Map<K, V>{
    Comparator
<? super K> comparator();
    SortedMap
<K, V> subMap(K fromKey, K toKey);
    SortedMap
<K, V> headMap(K toKey);
    SortedMap
<K, V> tailMap(K fromKey);
    K firstKey();
    K lastKey();
}

和SortedSet类似,SortedMap也提供了如下一些额外的操作:
  • Range view — performs arbitrary range operations on the sorted map
  • Endpoints — returns the first or the last key in the sorted map
  • Comparator access — returns the Comparator, if any, used to sort the map
·SortedMap得到的iterator是按顺序进行遍历的(Map没有顺序)
·toArray得到的数组是按序排列SortedMap中的元素的(Map没有顺序)

SortedMap (Java 2 Platform SE 6)

注意,如果有序映射要正确实现 Map 接口,则有序映射所维持的顺序(无论是否提供了明确的比较器)都必须与 equals 一致。(有关与 equals 一致 的精确定义,请参阅 Comparable 接口或 Comparator 接口)。这是因为 Map 接口是按照 equals 操作定义的,但有序映射使用它的 compareTo(或 compare)方法对所有键进行比较,因此从有序映射的角度来看,此方法认为相等的两个键就是相等的。即使顺序与 equals 不一致,树映射的行为仍然 定义良好的,只不过没有遵守 Map 接口的常规协定。

所有通用有序映射实现类都应该提供 4 个“标准”构造方法:1) void(无参数)构造方法,它创建一个空的有序映射,按照键的自然顺序进行排序。2) 带有一个 Comparator 类型参数的构造方法,它创建一个空的有序映射,根据指定的比较器进行排序。3) 带有一个 Map 类型参数的构造方法,它创建一个新的有序映射,其键-值映射关系与参数相同,按照键的自然顺序进行排序。4) 带有一个 SortedMap 类型参数的构造方法,它创建一个新的有序映射,其键-值映射关系和排序方法与输入的有序映射相同。无法保证强制实施此建议,因为接口不能包含构造方法。




总结

The Java Collections Framework hierarchy consists of two distinct interface trees:

  • The first tree starts with the Collection interface, which provides for the basic functionality used by all collections, such as add and remove methods. Its subinterfaces — Set, List, and Queue — provide for more specialized collections.

    The Set interface does not allow duplicate elements. This can be useful for storing collections such as a deck of cards or student records. The Set interface has a subinterface, SortedSet, that provides for ordering of elements in the set.

    The List interface provides for an ordered collection, for situations in which you need precise control over where each element is inserted. You can retrieve elements from a List by their exact position.

    The Queue interface enables additional insertion, extraction, and inspection operations. Elements in a Queue are typically ordered in on a FIFO basis.

  • The second tree starts with the Map interface, which maps keys and values similar to a Hashtable.

    Map's subinterface, SortedMap, maintains its key-value pairs in ascending order or in an order specified by a Comparator.




posted on 2008-07-03 21:54 This is Wing 阅读(325) 评论(0)  编辑  收藏 所属分类: Java基础

只有注册用户登录后才能发表评论。


网站导航:
 
 
Copyright © This is Wing Powered by: 博客园 模板提供:沪江博客