所使用的jdk版本为1.8版本,先看一下SortedMap在JDK中Map的UML类图中的位置:
2.1.2 SortedMap接口
SortedMap<K,V>继承Map<K,V>接口,是一个更进一步提供基于键key的总体排序的 Map。该映射是根据其键key的自然顺序(自然排序的定义可以参见java.lang.Comparable接口,就是实现该接口)进行排序的,或者根据通常在创建有序映射SortedMap时提供的 Comparator 进行排序。
插入有序映射的所有键都必须实现Comparable接口(或者被指定的比较器Comparator接受)。另外,所有这些键都必须是可互相比较的:对有序映射中的任意两个键k1和k2,执行k1.compareTo(k2)(或comparator.compare(k1, k2))都不得抛出ClassCastException。试图违反此限制将导致有问题的的方法或者构造方法调用抛出ClassCastException。
SortedMap<K,V>接口从定义来看比较简单,需要注意的就是其中的key要么实现Comparable接口要么被指定的比较器Comparator接受。接口定义描述建议所有的SortedMap实现类都应该提供四个标准的构造函数:
(1)void 无参的构造函数,此时按照键的自然顺序进行排序;
(2)只有一个 Comparator 类型参数的构造方法,它创建一个空的有序映射,并且根据指定的 Comparator进行排序;
(3)只有一个 Map 类型参数的构造方法,它创建一个新的有序映射,其键-值映射关系与参数Map相同,按照键的自然顺序进行排序;
(4)只有一个 SortedMap 类型参数的构造方法,它创建一个新的有序映射,其键-值映射关系和排序方法与入参的SortedMap相同。
因为接口中无法定义构造方法,无法保证以上四种方法一定就会被实现。最上面的图,SortedMap实现类TreeMap是全部实现了这四个构造方法的。
因为SortedMap定义相对简单,简单列一些里面的函数:
public interface SortedMap<K,V> extends Map<K,V> {
/**
* 返回对此映射中的键进行排序的比较器;如果使用的自然顺序,返回null
*/
Comparator<? super K> comparator();
/**
* 返回此映射的部分视图,其键值的范围从 fromKey(包括)到 toKey(不包括)。(如果 fromKey
* 和 toKey 相等,则返回映射为空。)返回的映射受此映射支持,所以在返回映射中的更改将反映在此
* 映射中,反之亦然。返回的映射支持此映射支持的所有可选映射操作。
* 如果试图在返回映射的范围之外插入键,则返回的映射将抛出 IllegalArgumentException。
*
* @param fromKey - 返回映射中key的低端点(包括)
* @param toKey - 返回映射中键的高端点(不包括)
* @return 此映射的部分视图,其键值的范围从 fromKey(包括)到 toKey(不包括)
* @throws ClassCastException - 如果无法使用此映射的比较器(如果此映射没有比较器,则使用
* 自然顺序)比较 fromKey 和 toKey。如果 fromKey 或 toKey 不能与映射中当前键进行比较,则
* 实现可以(但不是必须)抛出此异常。
* @throws NullPointerException - 如果 fromKey 或 toKey 为 null,并且此映射不允许使
* 用 null 键
* @throws IllegalArgumentException - 如果 fromKey 大于 toKey;如果此映射本身有范围限
* 制,并且 fromKey 或 toKey 位于范围的边界之外
*/
SortedMap<K,V> subMap(K fromKey, K toKey);
/**
* 返回此映射的部分视图,其键值严格小于 toKey。返回的映射受此映射支持,所以在返回映射中的更改
* 将反映在映射中,反之亦然。返回的映射支持此映射支持的所有可选映射操作。
*
* 如果试图在返回映射的范围之外插入键,则返回的映射将抛出 IllegalArgumentException。
*
* @param toKey 返回映射视图中键的高端点(不包括)
* @return 此映射的部分视图,且其中的键严格小于 toKey
* @throws ClassCastException 如果 toKey 与此映射的比较器不兼容(或者,如果该映射没有比
* 较器, 如果 toKey 没有实现 Comparable)。如果 toKey 不能与映射中的当前键进行比较,则实
* 现可以(但不是必须)抛出此异常。
* @throws NullPointerException 如果toKey为null,且该映射不允许key为null
* @throws IllegalArgumentException 如果此映射本身有范围限制,并且 toKey 位于范围的边界
* 之外
*/
SortedMap<K,V> headMap(K toKey);
/**
* 返回此映射的部分视图,其键大于等于 fromKey。返回的映射受此映射支持,所以在返回映射中的更改
* 将反映在映射中,反之亦然。返回的映射支持此映射支持的所有可选映射操作。
* 如果试图在返回映射的范围之外插入键,则返回的映射将抛出 IllegalArgumentException。
*
* @param fromKey 返回映射中键的低端点(包括)
* @return 此映射的部分视图,其中的键大于等于 fromKey
* @throws ClassCastException 如果 fromKey 与此映射的比较器不兼容(或者,如果该映射没有
* 比较器;如果 fromKey 没有实现 Comparable)。如果 fromKey 不能与映射中的当前键进行比
* 较,则实现可以(但不是必须)抛出此异常。
* @throws NullPointerException 如果 fromKey 为 null,并且此映射不允许使用 null 键
* @throws IllegalArgumentException 如果此映射本身有范围限制,并且 fromKey 位于范围的
* 边界之外
*/
SortedMap<K,V> tailMap(K fromKey);
/**
* 返回此映射中当前第一个(最低)键。
*
* @return 返回此映射中当前第一个(最低)键。
* @throws NoSuchElementException 如果map为空(即size() == 0)
*/
K firstKey();
/**
* 返回映射中当前最后一个(最高)键。
*
* @return 返回映射中当前最后一个(最高)键。
* @throws NoSuchElementException 如果map为空(即size() == 0)
*/
K lastKey();
/**
* 与父接口Map中的定义一样,但有顺序
*/
Set<K> keySet();
/**
* 与父接口Map中的定义一样,但有顺序(根据key的顺序)
*/
Collection<V> values();
/**
* 与父接口Map中的定义一样,但有顺序(根据key的顺序)
*/
Set<Map.Entry<K, V>> entrySet();
}
需要注意的地方:
1、subMap(K fromKey, K toKey)、headMap(K toKey)、tailMap(K fromKey),都是满足fromKey <= key < toKey;
2、firstKey()和lastKey()方法,当SortedMap对象为空(size() == 0)就会抛出NoSuchElementException异常;
3、subMap等子集map和当前sortedMap的元素变更是互相影响的。
以上注意点可以用TreeMap实现验证(后续会分析在TreeMap中的实现):
public static void main(String[] args) {
SortedMap<Integer, Integer> sortedMap = new TreeMap();
sortedMap.put(2,2);
sortedMap.put(4,4);
sortedMap.put(1,1);
System.out.println(sortedMap.subMap(1,2));
System.out.println(sortedMap.headMap(2));
System.out.println(sortedMap.tailMap(2));
//获取的子集中添加一个元素会影响当前sortedMap
SortedMap<Integer, Integer> subSortedMap = sortedMap.subMap(0,4);
subSortedMap.put(3,3);
//当前sortedMap增减元素会影响子集subSortedMap
sortedMap.put(0,0);
System.out.println(subSortedMap);
System.out.println(sortedMap);
}
程序输出结果:
{1=1}
{1=1}
{2=2, 4=4}
{0=0, 1=1, 2=2, 3=3}
{0=0, 1=1, 2=2, 3=3, 4=4}
以上,SortedMap<K,V>暂时写这么多~
题外话:这里发现一个值得玩味的地方,就是keySet()、values()、entrySet()三个方法在父接口Map已经有相同结构的方法定义了,在SortedMap中又重新定义了一次(不过返回的都是有顺序的)。JDK中还有很多类似这样子接口重新定义了父接口中方法情况,比如List接口中定义了和父接口Collection一样的size()、isEmpty()等,感觉这种更多是处于软件工程和设计模式等方面的考虑吧,不知诸位对此有何看法,欢迎留言赐教~