首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > JAVA > J2SE开发 >

TreeSet聚合为什么要实现Comparable

2013-11-12 
TreeSet集合为什么要实现Comparableimport java.util.*public class UpdateStu implements Comparable {S

TreeSet集合为什么要实现Comparable
import java.util.*;
public class UpdateStu implements Comparable {
String name;
long id;
public UpdateStu(String name, long id) {
this.id = id;
this.name = name;
}
public int compareTo(Object o) {
UpdateStu upstu = (UpdateStu) o;
int result = id > upstu.id ? 1 : (id == upstu.id ? 0 : -1);
return result;
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public static void main(String[] args) {
UpdateStu stu1 = new UpdateStu("李同学", 01011);
UpdateStu stu2 = new UpdateStu("陈同学", 01021);
UpdateStu stu3 = new UpdateStu("王同学", 01051);
UpdateStu stu4 = new UpdateStu("马同学", 01012);
TreeSet tree = new TreeSet();
tree.add(stu1);
tree.add(stu2);//这里就有问题了
tree.add(stu3);
tree.add(stu4);
Iterator it = tree.iterator();
System.out.println("Set集合中的所有元素:");
while (it.hasNext()) {
UpdateStu stu = (UpdateStu) it.next();
System.out.println(stu.getId() + " " + stu.getName());
}
it = tree.headSet(stu2).iterator();
System.out.println("截取前面部分的集合:");
while (it.hasNext()) {
UpdateStu stu = (UpdateStu) it.next();
System.out.println(stu.getId() + " " + stu.getName());
}
it = tree.subSet(stu2, stu3).iterator();
System.out.println("截取中间部分的集合");
while (it.hasNext()) {
UpdateStu stu = (UpdateStu) it.next();
System.out.println(stu.getId() + " " + stu.getName());
}
}
}
   我把上述代码implements Comparable 去掉,运行的时候会有错误,为什么
我检查到了是tree.add(stu1);
tree.add(stu2);//这里就有问题了
tree.add(stu3);
tree.add(stu4);
这里有问题的,那位能给我解释一下啊。。。。。。
[解决办法]
TreeSet是用TreeMap来实现的,他是按照一定顺序存放的,这个排序的依据就是所存放元素的compareTo方法,放第一个的时候无需跟任何元素比较,所以不报错,但是从第二个开始就要比较以决定放置的位置了,这时候就要调用compareTo方法,怎么调用compareTo方法呢,只有将类强制转换为Comparable类型之后才能调用啊,但是若你没有实现Comparable接口,那当然就不能强制准换了,所以就报java.lang.ClassCastException
[解决办法]
首先,让我们来看看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&nbsp;?&nbsp;e2==null&nbsp;:&nbsp;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接口




[解决办法]
引用:
引用:
TreeSet是用TreeMap来实现的,他是按照一定顺序存放的,这个排序的依据就是所存放元素的compareTo方法,放第一个的时候无需跟任何元素比较,所以不报错,但是从第二个开始就要比较以决定放置的位置了,这时候就要调用compareTo方法,怎么调用compareTo方法呢,只有将类强制转换为Comparable类型之后才能调用啊,但是若你没有实现Compara……


你这个添加的是字符串吧,java应该已经帮你实现了比较字符串大小的方法。
而你添加student类是自定义的,就需要自己实现Comparable 才行。

热点排行