TreeMap中是否能存储多个键为null的键值对

对于存储进TreeMap及TreeSet中的元素,要求元素自身具有比较性或者在创建集合时传入一个比较器对象。当调用TreeMap.put(key,value)时,如果root为空,也就是集合中没有元素时,不管key值是否为null,TreeMap都创建一个节点并将该节点作为树根节点存入集合中。当第二次存入key为null的键值对时,此时如果集合自身不带比较器,那么调用元素自身的compareTo()方法,即key.compareTo()方法,此时必然产生NullPointerException异常。例如,当创建一个存储键和值都是String类型,但自身不带比较器的TreeMap对象时,即TreeMap<String,String> tm= new TreeMap<String,String>();两次调用tm.put(null,”aaa”)时,第一次能顺利存入,因为TreeMap为空,直接创建一个根节点并将元素存入,但是第二次传入时,由于集合自身不带比较器,因此调用String.compareTo(String str)方法,必然产生空指针异常。


但是当集合自身带有比较器对象时,调用的是比较器Comparator.compare(K key,K k),此时是否能正常存入完全取决于比较器。因此,TreeMap中能否存入多个键值为null的键值对取决于集合自带比较器。下面是TreeMap.put(K key,V value)源码分析。

public V put(K key, V value) {

       Entry<K,V> t = root;

//如果根节点为空,也就是集合中没有元素,直接创建一个Entry节点并存入集合中,并将该节点作为root

       if (t == null) {

           compare(key, key); // type (and possibly null) check

 

           root = new Entry<>(key, value, null);

           size = 1;

           modCount++;

           return null;

       }

//如果集合自身带有比较器对象,优先使用集合自带的比较器,调用比较器的compare方法,在树中找一个合适位置并记录它的父亲节点

       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 {

//如果使用元素自身的compareTo方法,则key必须非空,只要为空,就产生空指针异常

           if (key == null)

                throw newNullPointerException();

//在树中找到一个合适位置,并记录它的父亲节点

           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;

       else

           parent.right = e;

       fixAfterInsertion(e);

       size++;

       modCount++;

       return null;

    }

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
TreeMap和HashMap都是Java的Map接口的实现类,它们都可以用于存储键值对。但是它们的底层实现方式不同,因此它们在某些方面有所不同。 下面是TreeMap和HashMap的比较: 1. TreeMap是有序的,而HashMap是无序的。这是因为TreeMap实现了SortedMap接口,而HashMap没有实现该接口。 2. TreeMap的底层是由树(红黑树)实现的,而HashMap是由哈希桶实现的。由于哈希算法本身的优势,我们再进行增删查改的时候,HashMap的时间复杂度是O(1),是通过哈希函数计算的哈希地址。而我们的红黑树就不具有这样的优势,时间复杂度是O(log2n)。 3. TreeMap和HashMap都可以存储null值,但是HashMap只能有一个null键,而TreeMap可以有多个null键。 4. TreeMap和HashMap都不是线程安全的,如果需要在多线程环境下使用,需要进行额外的同步处理。 下面是一个使用TreeMap的例子: ```java import java.util.TreeMap; public class TreeMapExample { public static void main(String[] args) { // 创建一个TreeMap对象 TreeMap<String, Integer> treeMap = new TreeMap<>(); // 添加键值对 treeMap.put("apple", 1); treeMap.put("banana", 2); treeMap.put("orange", 3); // 获取键值对 System.out.println(treeMap.get("apple")); // 输出:1 // 遍历键值对 for (String key : treeMap.keySet()) { System.out.println(key + ": " + treeMap.get(key)); } } } ``` 下面是一个使用HashMap的例子: ```java import java.util.HashMap; public class HashMapExample { public static void main(String[] args) { // 创建一个HashMap对象 HashMap<String, Integer> hashMap = new HashMap<>(); // 添加键值对 hashMap.put("apple", 1); hashMap.put("banana", 2); hashMap.put("orange", 3); // 获取键值对 System.out.println(hashMap.get("apple")); // 输出:1 // 遍历键值对 for (String key : hashMap.keySet()) { System.out.println(key + ": " + hashMap.get(key)); } } } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值