TreeMap 按照 Key 的排序结果来组织内部结构的Map类集合,它改变了Map类散乱无序的形象。虽然TreeMap没有ConcurrentHashMap 和 HashMap 普及,但是在Key有排序的要求的场景下,使用 TreeMap 可以事半功倍。在集合框架如中,他们都继承AbstractMap 抽象类,TreeMap 与 HashMap 、ConcurrentHashMap 的类图关系如下:
- TreeMap 继承于AbstractMap,所以它是一个Map,即一个key-value集合。
- TreeMap 实现了 SortedMap 接口,表示它的Key是有序的。支持获取头尾 Key-Value 元素,或者根据Key指定范围获取子集合等。插入的Key 必须实现Comparable 或者 提供额外的比较器 Comparator,所以Key不允许为null, 但是Value可以
- TreeMap 实现 NavigableMap 接口继承了 SortedMap 接口,根据指定的搜索条件返回最匹配的Key-Value元素。不同于HashMap,TreeMap 并非一定要覆写hashCode 和 equals 方法来达到Key去重的目的。
- TreeMap 实现了Cloneable接口,意味着它能被克隆。
- TreeMap 实现了java.io.Serializable接口,意味着它支持序列化。
public class TreeMapTest {
public static void main(String[] args) {
//如果把此处的TreeMap 换成 HashMap ,则 size = 1
TreeMap treeMap = new TreeMap();
treeMap.put(new Key(),"value one");
treeMap.put(new Key(),"value two");
// TreeMap ,size = 2 , 因为Key 去重规是根据排序结果
System.out.println(treeMap.size());
}
static class Key implements Comparable<Key>{
@Override
public int compareTo(Key o) {
//返回负数的常数,表示此对象永远小于输入的other对象,此处决定TreeMap的size=2
return -1;
}
@Override
public int hashCode() {
return 1;
}
@Override
public boolean equals(Object obj) {
return true;
}
}
}
上面的例子,如果把TreeMap 换成 HashMap ,size的结果则从2变成1。
注意 HashMap 是使用 hashCode 和 equals 实现去重的。
而TreeMap 则依靠Comparable 或 Comparator 来实现Key的 去重,
TreeMap 有两种排序:
- 自然排序: TreeMap 的所有Key必须实现 Comparable 接口,而且所有的key应该是同一个类的对象,否则将会抛出 ClassCastException 异常。
- 定制排序: 创建TreeMap 时,传入一个Comparator对象,该对象负责对TreeMap中的所有key进行排序。采用定制排序时不要求Map的key实现 Comparable接口。
如果没有覆盖正确的方法,那么TreeMap 的最大特性将无法发挥出来,甚至在运行时出现异常。如果要用TreeMap对Key进行排序,调用如下方法:
final int compare(Object k1, Object k2) {
return comparator==null ? ((Comparable<? super K>)k1).compareTo((K)k2)
: comparator.compare((K)k1, (K)k2);
}
如果 comparator 不为null, 优先使用 comparator 的compare方法;
如果为null, 则使用Key实现的自然排序Comparable接口的 compareTo 方法。如果两者都无法满足,则抛出异常;
Exception in thread "main" java.lang.ClassCastException: com.yaspeed2.TreeMapTest$Key cannot be cast to java.lang.Comparable
at java.util.TreeMap.compare(TreeMap.java:1294)
at java.util.TreeMap.put(TreeMap.java:538)
at com.yaspeed2.TreeMapTest.main(TreeMapTest.java:9)
TreeMap 中判断两个key 相等的标准是: 两个key通过compareTo() 方法返回0,TreeMap 即认为这两个key是相等的。
如果使用自定义类作为TreeMap的key, 且让TreeMap 良好的工作,则重写该类的equals() 方法和compareTo() 方法时应保持一致的返回结果: 两个key 通过equals() 方法比较返回true时,他们通过compareTo() 返回比较应该返回0。如果equals()方法与compareTo()方法的返回结果不一致,TreeMap与Map接口的规则就会冲突。