关于List,Set,Map能否存储null


 

本文源码为jdk1.8版本

喵的,今天面试问这个卡壳了,明明我之前看了的,邀请面试的是你,拒绝我的也是你,你为什么那么熟练啊QAQ

    @Test
    public void testArrayList(){ ArrayList<String> list = new ArrayList<>(); list.add(null); list.add(null); Assert.assertEquals(2,list.size()); // success } @Test public void testLinkedList(){ LinkedList<String> list = new LinkedList<>(); list.add(null); list.add(null); Assert.assertEquals(2,list.size()); // success } 

首先是List,可以看到ArrayList可以存储多个null,ArrayList底层是数组,添加null并未对他的数据结构造成影响。LinkedList底层为双向链表,node.value = null也没有影响。


@Test
    public void testHashMap(){ HashMap<String,String> map = new HashMap<>(); map.put(null,null); Assert.assertEquals(1,map.size()); //OK size = 1 map.put(null,null); Assert.assertEquals(2,map.size()); //Error size = 1 } @Test public void testTreeMap(){ TreeMap<String,String> map = new TreeMap<>(); map.put(null,null); Assert.assertEquals(1,map.size()); //Error NullPointException } 

关于Map,HashMap中最多只有一个key == null的节点,因为key相同时,后面的节点会替换之前相同key的节点,所以HashMap是可以添加key == null 的节点的,只不过只会存在一个,有兴趣的话可以去看源码(tips:源码真的眼花缭乱,可以尝试自己写上注释,更容易看懂,菜鸟的方法)put方法返回旧值。TreeMap的put方法会调用compareTo方法,对象为null时,会报空指针错。


    @Test public void testHashSet(){ HashSet<String> set = new HashSet<>(); set.add(null); Assert.assertEquals(1,set.size()); //OK size = 1 set.add(null); Assert.assertEquals(2,set.size()); //Error size = 1 } @Test public void testTreeSet(){ TreeSet<String> set = new TreeSet<>(); set.add(null); //Error NullPointException } 

最后是Set,HashSet底层是HashMap,所以它的put()如下,也只能有一个null。

    private static final Object PRESENT = new Object(); public boolean add(E e) { return map.put(e, PRESENT)==null; } 

TreeSet的put()也是如此。

    public boolean add(E e) { return m.put(e, PRESENT)==null; } 
  • 结果:
  • List都可以添加null元素
  • HashMap可以有1个key为null的元素,TreeMap不能有key为null的元素
    Set底层是Map
  • 所以HashSet可以有1个null的元素,TreeSet不能有key为null的元素。

面试官,您看您还要我吗?

续上:

  • Vector 底层是数组,所以不会管你元素的内容是什么,可以存储多个null
    @Test public void VectorTest(){ Vector box = new Vector(); box.add(null); box.add(null); Assert.assertEquals(2,box.size()); //ok } /** *此为Vector的add函数 **/ public synchronized boolean add(E e) { modCount++; ensureCapacityHelper(elementCount + 1); elementData[elementCount++] = e; return true; } 
  • HashTable底层为散列表,无论是key为null,还是value为null,都会报错
    @Test public void HashTableTest(){ Hashtable table = new Hashtable(); //table.put(new Object(),null); //Exception //table.put(null,new Object()); //Exception //table.put(null,null); //Exception Assert.assertEquals(1,table.size()); } //此为hashTable#put函数源码 public synchronized V put(K key, V value) { // Make sure the value is not null if (value == null) { //value 需要判空,所以value不可为null throw new NullPointerException(); } // Makes sure the key is not already in the hashtable. Entry<?,?> tab[] = table; int hash = key.hashCode(); //key需要拥有实例去调用hashCode方法,所以也不能为空 int index = (hash & 0x7FFFFFFF) % tab.length; @SuppressWarnings("unchecked") Entry<K,V> entry = (Entry<K,V>)tab[index]; for(; entry != null ; entry = entry.next) { if ((entry.hash == hash) && entry.key.equals(key)) { V old = entry.value; entry.value = value; return old; } } addEntry(hash, key, value, index); return null; } 

至于为什么hashtable键和值都设计成不能为null,牛客网的一位大佬这样说到:

 

 

以上。


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM