TreeMap是使用红黑二叉树来实现的,底层实现较麻烦,暂时学会使用,待后续再深入研究。
TreeMap的关键源码:
private transient Entry<K,V> root;
其中root用来存储整个树的根节点。进入Entry(是TreeMap的内部类)的代码:
/**
* Node in the Tree. Doubles as a means to pass key-value pairs back to
* user (see Map.Entry).
*/
static final class Entry<K,V> implements Map.Entry<K,V> {
K key;
V value;
Entry<K,V> left;
Entry<K,V> right;
Entry<K,V> parent;
boolean color = BLACK;
......
}
这是树上的一个节点,里面存储了本身数据、左节点、右节点、父节点、以及节点颜色。
TreeMap和HashMap实现了同样的接口Map。HashMap效率高于TreeMap;在需要排序的Map时才选用TreeMap。
HashMap与HashTable的区别
HashMap: 线程不安全,效率高。允许key或value为null。
HashTable: 线程安全,效率低。不允许key或value为null。
下面直接看实现TreeMap的程序:
package myhashmap;
import java.util.Map;
import java.util.TreeMap;
/**
* 测试TreeMap的使用
*
* @author 发达的范
* @date 2020/11/16 22:17
*/
public class TestTreeMap01 {
public static void main(String[] args) {
Map<Integer, String> treeMap = new TreeMap<>();
treeMap.put(15, "唐僧");
treeMap.put(06, "孙悟空");
treeMap.put(19, "猪八戒");
treeMap.put(23, "沙和尚");
//TreeMap内部自动按照key递增的方式排序
for (Integer key : treeMap.keySet()) {
System.out.println(key + ":" + treeMap.get(key));
}
}
}
运行结果:
可见,向TreeMap中put数据时是乱序的,输出是按照V升序排序。排序是TreeMap内部基于红黑二叉树自动实现。回想一下上一节中测试HashMap的程序,并未排序按照输入的顺序输出。
我们知道容器是可以放置包含任何对象的键值对,上面只是实现了放置Integer类型的键,下面测试使用自定义的实现类存入TreeMap中:
package myhashmap;
import java.util.Map;
import java.util.TreeMap;
/**
* 测试TreeMap的使用
*
* @author 发达的范
* @date 2020/11/17 21:00
*/
public class TestTreeMap02 {
public static void main(String[] args) {
Map<Student, String> studentTreeMap = new TreeMap<>();
studentTreeMap.put(new Student(001, "唐三藏", 175), "我是唐三藏");//向TreeMap中put键值对
studentTreeMap.put(new Student(002, "孙悟空", 170), "我是孙悟空");
studentTreeMap.put(new Student(003, "猪八戒", 185), "我是猪八戒");
studentTreeMap.put(new Student(004, "沙和尚", 165), "我是沙和尚");
studentTreeMap.put(new Student(005, "白龙马", 165), "我是白龙马");
//使用增强for循环遍历TreeMap
for (Student key : studentTreeMap.keySet()) {
System.out.println(key + ":" + studentTreeMap.get(key));
}
}
}
class Student implements Comparable<Student> {
int id;
String name;
double height;
public Student(int id, String name, double height) {
this.id = id;
this.name = name;
this.height = height;
}
//实现了Comparable接口,就需要实现Comparable接口的所有方法(只有一个comparaTo方法)
@Override
public int compareTo(Student o) {
if (this.height > o.height) {
return 1;
} else if (this.height < o.height) {
return -1;
} else {
if (this.id > o.id) {
return 1;
} else if (this.id < o.id) {
return -1;
} else {
return 0;
}
}
}
//需要重写toString方法才能正确输出
@Override
public String toString() {
return "id:" + id + " name:" + name + " height:" + height;
}
}
运行结果:
从运行结果可以看出,所有对象按照height升序排列,如果height相同就按照id升序排列。
由于TreeMap的底层原理是使用红黑二叉树实现的,我还没有学习,所以对TreeMap的底层实现以及节点的存储方式还不熟悉。下面说一下我对TreeMap的理解:
红框里面是键值对,我不管你是怎么存储的,你在TreeMap的内存中就是一个整体,只是按照键Integer进行排序的,所以也就有了:
红框里面都是键值对,是一个整体,只是现在使用自定义的一个类作为键key(K),TreeMap内部需要在树上进行自动排序,我指定了它的排序规则(重写compareTo()方法)。