TreeSet存储原则是:不可重复,有序的。
public TreeSet() { this(new TreeMap<E,Object>()); }
public TreeSet(Comparator<? super E> comparator) { this(new TreeMap<>(comparator)); }
上面是TreeSet常用的两个构造函数。
底层实现也就是TreeMap。
TreeSet(NavigableMap<E,Object> m) { this.m = m; }
/** * The backing map. */ private transient NavigableMap<E,Object> m; // Dummy value to associate with an Object in the backing Map private static final Object PRESENT = new Object();
维护了上面两个变量。
add方法
public boolean add(E e) { return m.put(e, PRESENT)==null; }
因为TreeMap存储的是键值对,因此他将要保存的元素作为key,以一个常量作为值保存到TreeMap中。
这就是为什么TreeSet保存的元素是不可重复的了,因为TreeMap的键不可以重复。
到这里TreeSet也差不多分析完了,主要还是分析TreeMap,因为实现在他里面。
TreeMap常用构造函数:
public TreeMap(Comparator<? super K> comparator) { this.comparator = comparator; }
public TreeMap() { comparator = null; }
这里Comparator是一个比较器,这就是为什么TreeSet是有序的原因了。
private final Comparator<? super K> comparator; private transient Entry<K,V> root = null;
上面两个主要变量,一个是比较器,一个是根。这个根是因为数据结构而设计的,一种红黑树或者叫二叉树的一种数据结构。TreeMap也是根据这个数据结构而设计的。
好,我们来看看添加元素的真面目吧。
public V put(K key, V value) { Entry<K,V> t = root;//得到根节点 if (t == null) {//添加第一个元素 compare(key, key); // type (and possibly null) check root = new Entry<>(key, value, null);//根节点就是第一个添加进来的元素,前一个节点为null size = 1; modCount++; return null; } int cmp; Entry<K,V> parent; // split comparator and comparable paths Comparator<? super K> cpr = comparator; if (cpr != null) {//有比较器 do { parent = t;//从根节点出发 cmp = cpr.compare(key, t.key);//新添加进来的元素和根节点比较 if (cmp < 0)//小了,放左边 t = t.left; else if (cmp > 0)//大了,放右边 t = t.right; else return t.setValue(value);//相等直接返回,且将新的元素值替换掉旧的 } while (t != null);//直到没有左右节点 } else { if (key == null) throw new NullPointerException(); Comparable<? super K> k = (Comparable<? super K>) key; do { parent = t; cmp = k.compareTo(t.key);//根据自然排序 if (cmp < 0) t = t.left; else if (cmp > 0) t = t.right; else return t.setValue(value); } while (t != null); } Entry<K,V> e = new Entry<>(key, value, parent); if (cmp < 0) parent.left = e;//此时,parent元素的值最小,新元素的值比parent还小,放在parent左边 else parent.right = e;//此时,parent元素的值最最大,新元素的值比parent还大,放在parent右边 fixAfterInsertion(e); size++; modCount++; return null; }
好,现在元素放进去了,要取出来吧。使用iterator()方法。
//TreeSet public Iterator<E> iterator() { return m.navigableKeySet().iterator(); }
TreeSet的iterator方法是调用了TreeMap的方法。这个方法是从JDK1.6开始有的
/** * @since 1.6 */ public NavigableSet<K> navigableKeySet() { KeySet<K> nks = navigableKeySet; return (nks != null) ? nks : (navigableKeySet = new KeySet(this)); }
实际上就是调用了KeySet的iterator方法。