小结

SortedMap在遍历时严格按照Key的顺序遍历,最常用的实现类是TreeMap;
作为SortedMap的Key必须实现Comparable接口,或者传入Comparator;
要严格按照compare()规范实现比较逻辑,否则,TreeMap将不能正常工作。

HashMap是一种以空间换时间的映射表,它的实现原理决定了内部的Key是无序的,即遍历HashMap的Key时,其顺序是不可预测的(但每个Key都会遍历一次且仅遍历一次)。
还有一种Map,它在内部会对Key进行排序,这种Map就是SortedMap。注意到SortedMap是接口,它的实现类是TreeMap

int 等基本类型不能用comparable接口,需要用包装类型
使用TreeMap时,放入的Key必须实现Comparable接口。String、Integer这些类已经实现了Comparable接口,因此可以直接作为Key使用。作为Value的对象则没有任何要求。
如果作为Key的class没有实现Comparable接口,那么,必须在创建TreeMap时同时指定一个自定义排序算法:

  1. public class Main {
  2. public static void main(String[] args) {
  3. Map<Person, Integer> map = new TreeMap<>(new Comparator<Person>() {
  4. @Override
  5. public int compare(Person p1, Person p2) {
  6. return p1.name.compareTo(p2.name);
  7. }
  8. });
  9. map.put(new Person("Tom"), 1);
  10. map.put(new Person("Bob"), 2);
  11. map.put(new Person("Lily"), 3);
  12. for (Person key : map.keySet()) {
  13. System.out.println(key);
  14. }
  15. // {Person: Bob}, {Person: Lily}, {Person: Tom}
  16. System.out.println(map.get(new Person("Bob"))); // 2
  17. }
  18. }
  19. class Person {
  20. public String name;
  21. Person(String name) {
  22. this.name = name;
  23. }
  24. public String toString() {
  25. return "{Person: " + name + "}";
  26. }
  27. }

注意到Comparator接口要求实现一个比较方法,它负责比较传入的两个元素a和b,如果ab,则返回正数,通常是1。TreeMap内部根据比较结果对Key进行排序。
从上述代码执行结果可知,打印的Key确实是按照Comparator定义的顺序排序的。如果要根据Key查找Value,我们可以传入一个new Person(“Bob”)作为Key,它会返回对应的Integer值2。
另外,注意到Person类并未覆写equals()和hashCode(),因为TreeMap不使用equals()和hashCode()

如果作为Key的class没有实现Comparable接口,那么,必须在创建TreeMap时同时指定一个自定义排序算法:

  1. public class MM {
  2. public static void main(String[] args) {
  3. Map<Student, Integer> map = new TreeMap<>(new Comparator<Student>() {
  4. public int compare(Student p1, Student p2) {
  5. return p1.score > p2.score ? -1 : 1;
  6. // return p1.score.compareTo(p2.score);
  7. }
  8. });
  9. map.put(new Student("Tom", 77), 1);
  10. map.put(new Student("Bob", 66), 2);
  11. map.put(new Student("Lily", 99), 3);
  12. for (Student key : map.keySet()) {
  13. System.out.println(key);
  14. }
  15. System.out.println(map.get(new Student("Bob", 66))); // null? 把上面代码改成注掉的就可以
  16. }
  17. }
  18. class Student {
  19. public String name;
  20. public Integer score;
  21. Student(String name, Integer score) {
  22. this.name = name;
  23. this.score = score;
  24. }
  25. public String toString() {
  26. return String.format("{%s: score=%d}", name, score); //format使用指定的格式字符串和参数返回格式化字符串
  27. }
  28. }
  29. {Lily: score=99}
  30. {Tom: score=77}
  31. {Bob: score=66}
  32. null

解决15行的小问题