首先,让我们来看看JDK中TreeSet类的add方法
/** * Adds the specified element to this set if it is not already present. * More formally, adds the specified element {@code e} to this set if * the set contains no element {@code e2} such that * <tt>(e==null ? e2==null : e.equals(e2))</tt>. * If this set already contains the element, the call leaves the set * unchanged and returns {@code false}. * * @param e element to be added to this set * @return {@code true} if this set did not already contain the specified * element * @throws ClassCastException if the specified object cannot be compared * with the elements currently in this set * @throws NullPointerException if the specified element is null * and this set uses natural ordering, or its comparator * does not permit null elements */ public boolean add(E e) { return m.put(e, PRESENT)==null; }
注意抛出的异常~~
* @throws ClassCastException if the specified object cannot be compared with the elements currently in this set
也就是说,如果添加的元素不能和已有元素做比较就抛出ClassCastException异常~
那两个元素如果判断可比呢?
有两种办法,其中一种就是实现 Comparable接口
JDK中很多类都实现了Comparable接口,比如Integer
至于TreeSet为什么要这样设计,是因为这个类需要实现元素排序的功能
那如何实现的排序呢?
我们来看 TreeSet的构造方法
/** * Constructs a new, empty tree set, sorted according to the * natural ordering of its elements. All elements inserted into * the set must implement the {@link Comparable} interface. * Furthermore, all such elements must be <i>mutually * comparable</i>: {@code e1.compareTo(e2)} must not throw a * {@code ClassCastException} for any elements {@code e1} and * {@code e2} in the set. If the user attempts to add an element * to the set that violates this constraint (for example, the user * attempts to add a string element to a set whose elements are * integers), the {@code add} call will throw a * {@code ClassCastException}. */ public TreeSet() { this(new TreeMap<E,Object>()); }
/** * Constructs a set backed by the specified navigable map. */ TreeSet(NavigableMap<E,Object> m) { this.m = m; }
你可以发现,排序功能实际上是由TreeMap实现的
TreeSet的add方法实际上就是调用的的TreeMap的put方法~~
最后~看看put方法的源码
/** * Associates the specified value with the specified key in this map. * If the map previously contained a mapping for the key, the old * value is replaced. * * @param key key with which the specified value is to be associated * @param value value to be associated with the specified key * * @return the previous value associated with <tt>key</tt>, or * <tt>null</tt> if there was no mapping for <tt>key</tt>. * (A <tt>null</tt> return can also indicate that the map * previously associated <tt>null</tt> with <tt>key</tt>.) * @throws ClassCastException if the specified key cannot be compared * with the keys currently in the map * @throws NullPointerException if the specified key is null * and this map uses natural ordering, or its comparator * does not permit null keys */ public V put(K key, V value) { Entry<K,V> t = root; if (t == null) { // TBD: // 5045147: (coll) Adding null to an empty TreeSet should // throw NullPointerException // // compare(key, key); // type check root = new Entry<K,V>(key, value, 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<K,V>(key, value, parent); if (cmp < 0) parent.left = e; else parent.right = e; fixAfterInsertion(e); size++; modCount++; return null; }
你可以发现,这个二叉树排序中有一条这样的语句来判断大小
cmp = k.compareTo(t.key);
这里k,也就是我们TreeSet.add(k) 方法传入的参数
Comparable<? super K> k = (Comparable<? super K>) key;
可见,插入TreeSet的对象必须实现Compareble接口