本文源碼為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,牛客網的一位大佬這樣說到:

以上。