TreeSet.add()方法一细节

最近在一次使用TreeSet.add()方法中遇到了一个很迷惑的问题:往一个TreeSet集合中添加几个对象的时候发现有些没有添加进去,一开始是怀疑hashcode与equals的问题,因为Set集合是不允许添加两个相同对象的,但经查检确认没有问题,几经测试发现是传入的Comporator对象引起的(即使用的是TreeSet(Comparator<? super
E> comparator)构造方法),当其compare()方法返回0时,只能添加进一个对象,只要当前添加的对象与集合中的任意一个对象比较时compare()方法返回0,那么该对象就添加不进去。以前一直以为compare()方法返回0时只是两个对象的排列顺序不确定,后经查看源码才明白其中的原因。

下面是TreeSet的add()方法源码:

public boolean add(E e) {
	return m.put(e, PRESENT)==null;
}

其中m是一个TreeMap对象,其为TreeSet的实现是使用TreeMap的key部分来实现的,PRESENT是一个Object对象,纯粹是为了补全方法参数而已,下面是TreeMap.put()方法源码:

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);  //比较两个元素的key值,也就是Set中元素的值
            if (cmp < 0) //如果小于0则放到当前元素的左边
                t = t.left;
            else if (cmp > 0) //如果大于0则放到当前元素的右边
                t = t.right;
            else
                return t.setValue(value);  //否则,即返回0时调用java.util.TreeMap.Entry.setValue(value)方法
        } while (t != null);
    }
    //后面代码省略......
}

下面是java.util.TreeMap.Entry.setValue(value)方法源码:

public V setValue(V value) {
    V oldValue = this.value;
    this.value = value;
    return oldValue;
}

可以看到更新了值后把以前的值返回了。所以当compare方法的返回值为了时,TreeMap.put()方法只是返回的是被替换掉的值,根本就没有加入新的元素,当然m.put(e, PRESENT)==null 返回的也为false了。

时间: 2024-07-29 14:47:25

TreeSet.add()方法一细节的相关文章

java 17 - 6 TreeSet集合及其add()方法的源码解析

TreeSet:能够对元素按照某种规则进行排序. 排序有两种方式 A:自然排序 B:比较器排序 TreeSet集合的特点:排序和唯一 1 public class TreeSetDemo { 2 public static void main(String[] args) { 3 // 创建集合对象 4 // 自然顺序进行排序 5 TreeSet<Integer> ts = new TreeSet<Integer>(); 6 7 // 创建元素并添加 8 // 20,18,23,2

TreeSet集合的add()方法源码解析(01.Integer自然排序)

>TreeSet集合使用实例 >TreeSet集合的红黑树 存储与取出(图) >TreeSet的add()方法源码     TreeSet集合使用实例 package cn.itcast_05; import java.util.TreeSet; /* * TreeSet:能够对元素按照某种规则进行排序. * 排序有两种方式 * A:自然排序 * B:比较器排序 * * TreeSet集合的特点:排序和唯一 * * 通过观察TreeSet的add()方法,我们知道最终要看TreeMap的

TreeSet有趣问题之add方法原理

先看如下代码 class Worker implements Comparable<Worker> { private int age; private String name; public Worker(int age, String name) { this.setAge(age); this.setName(name); } @Override public int hashCode() { final int prime = 31; int result = 1; result =

jquery的add()方法扩大选择返回

1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <script type="text/javascript" src="jquery-1.11.3.min.js"></script> 6 <title>Title</title> 7 &

多线程对比linkedList和arrayList的add方法

上上一篇对linkedList和arrayList的源码对比:http://blog.csdn.net/aaashen/article/details/44925181 上一篇对linkedList和arrayList的各种方法进行单线程的对比:http://blog.csdn.net/aaashen/article/details/45011365 本篇用多线程对比,之对比add方法,插10000000条数据. 其中arrayList add 数据花费11615,linkedlist add数

在Vue的构造器里我们写一个add方法,然后我们用实例的方法调用它

html <div id="app"> <div>{{message}}</div> </div> js var vm = new Vue({ el:"#app", data:{ message:"HelloWorld" }, methods:{ add:function(a){ console.log(a) } } }) // 外部调用 vm.add("实例调用内部add方法"

thinkphp3.2.3 数据库写入add 方法的一些问题。

最近在做项目中遇到的一个数据操作add()方法,在不开启debug的模式下会漏掉一些字段没写入数据库. 当时并不知道是这个原因,明明在开发的时候都是没问题的,怎么突然出现这个问题,找了好久都没有头绪,实在没办法只好百度了. 后来在thinkphp的官方论坛上找到了一个解决的方法,说是因为缓存的问题,这时忽然想起了在上线的时候把debug模式关了,果断的去把debug模式打开试了一下 还真是这么回事.但是thinkphp官方并没有给什么解释.解决方法其实也很简单就是将对应应用下runtime目录下

关于 List add方法

add是将传入的参数作为当前List中的一个Item存储,即使你传入一个List也只会另当前的List增加1个元素addAll是传入一个List,将此List中的所有元素加入到当前List中,也就是当前List会增加的元素个数为传入的List的大小  eg: result.addAll(list);//把list中的每一个元素加到result中,result.size()==list.size() result.add(list);//将list作为一个元素加到result中,则result.s

TP add方法参数详解

tp add()方法参数详解: add($data='',$options=array(),$replace=false); 其中R$replace表示,是否添加数据时覆盖原有数据true表示覆盖,false表示不覆盖