TreeSet集合的add()方法的源码解析

用TreeSet存储Integer类型数据并遍历

  20,18,23,22,17,24,19,18,24

 1 package cn.itcast_05;
 2 
 3 import java.util.TreeSet;
 4 
 5 /*
 6  * TreeSet:能够对元素按照某种规则进行排序。
 7  *         排序有两种方式(具体那种方式取决于使用TreeSet的构造方法)
 8  *             A:自然排序
 9  *             B:比较器排序
10  * 
11  * TreeSet集合的特点:排序和唯一
12  * 
13  * 通过观察TreeSet的add()方法,我们知道最终要看TreeMap的put()方法。
14  */
15 public class TreeSetDemo {
16     public static void main(String[] args) {
17         // 创建集合对象
18         // TreeSet的无参构造:自然顺序进行排序
19         TreeSet<Integer> ts = new TreeSet<Integer>();
20 
21         // 创建元素并添加进集合
22         // 20,18,23,22,17,24,19,18,24
23         // Integer i1 = new Integer(200);
24         // ts.add(i1);
25         ts.add(20); // 自动装箱
26         ts.add(18);
27         ts.add(23);
28         ts.add(22);
29         ts.add(17);
30         ts.add(24);
31         ts.add(19);
32         ts.add(18);
33         ts.add(24);
34 
35         // 遍历集合
36         for (Integer i : ts) {
37             System.out.println(i);
38         }
39     }
40 }

TreeSet集合的add()方法的源码

---------------------------------------
interface Collection {
    ...
}

interface Set extends Collection {
    ...
}
---------------------------------------
class TreeSet implements Set {
    ...
    private static final Object PRESENT = new Object();
    private transient NavigableMap<E,Object> m;
    
    public TreeSet() {
         this(new TreeMap<E,Object>());
    }

    public boolean add(E e) {
        return m.put(e, PRESENT)==null;
    }
    ...
}
---------------------------------------
class TreeMap implements NavigableMap {
    ...
    public V put(K key, V value) {
       Entry<K,V> t = root; // 先造根,TreeSet集合底层数据结构是红黑树(是一个自平衡的二叉树)
       if (t == null) {
           compare(key, key); // type (and possibly null) check

           root = new Entry<>(key, value, null);
           size = 1;
           modCount++;
           return null;
       }
       
       int cmp;
       Entry<K,V> parent;
       // split comparator and comparable paths
       Comparator<? super K> cpr = comparator; // 因为用的是TreeSet的无参构造方法,是自然排序,没有用到comparator比较器
       if (cpr != null) {                      // 所以此时的comparator = null,则程序执行else里面的代码
           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; // 此接口Comparable强行对实现它的每个类的对象进行整体排序。这种排序被称为类的自然排序,类的 compareTo 方法被称为它的自然比较方法。。
           do {                                                   // 举例中我们使用的是包装类Intrger,而Integer类实现了Comparable接口。此例子是向上转型。
               parent = t;
               cmp = k.compareTo(t.key); // 类的 compareTo 方法被称为它的自然比较方法。
               if (cmp < 0)              // int compareTo(T o) 比较此对象与指定对象的顺序。如果该对象小于、等于或大于指定对象,则分别返回负整数、零或正整数。 
                   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;
       else
           parent.right = e;
       fixAfterInsertion(e);
       size++;
       modCount++;
       return null;
   }
   ...
}
---------------------------------------
    由上可知:真正的比较是依赖于元素的compareTo()方法,而这个方法compareTo()是定义在 Comparable接口里面的(抽象方法)。
    所以,你要想重写该方法,就必须是先实现 Comparable接口。这个接口表示的就是自然排序。
---------------------------------------

 

posted @ 2018-03-27 23:32  黑泽君  阅读(1276)  评论(0编辑  收藏  举报