我正在使用鏈表的java.util實現。我想知道爲什麼它允許我們添加空元素,我們甚至可以遍歷它們?爲什麼我們可以將null元素添加到java LinkedList中?
如果我們添加null元素並嘗試迭代它,那麼這不會破壞鏈表的點,我們有一個指向下一個元素的元素,而鏈表的常規實現會中斷。
我正在使用鏈表的java.util實現。我想知道爲什麼它允許我們添加空元素,我們甚至可以遍歷它們?爲什麼我們可以將null元素添加到java LinkedList中?
如果我們添加null元素並嘗試迭代它,那麼這不會破壞鏈表的點,我們有一個指向下一個元素的元素,而鏈表的常規實現會中斷。
看看Java 7的源代碼,LinkedList
被實現爲一系列節點。
private static class Node<E> {
E item;
Node<E> next;
Node<E> prev;
Node(Node<E> prev, E element, Node<E> next) {
this.item = element;
this.next = next;
this.prev = prev;
}
}
每個節點都有一個參考前面的節點和下一個節點,以及一個item
。將空值插入列表中時,您插入的節點的item
值爲null
,但next
和prev
指針非空。
從概念上講,Java集合持有指向對象的指針而不是對象本身。當你看到List<String>
認爲List<Pointer-to-String>
。您可以將相同字符串地址的多個副本存儲在集合中。多個集合可以共享相同的對象指針,並且可以將空指針存儲在集合中。
您正在考慮將「指針」添加到結構本身的「常規」實現。 Java通過引入一個包含指向另一個指針的「標題」對象和一個指向你放入的對象的指針,從而將「鏈接」的細節與代碼分開。指向你的對象的指針可以爲null。在內部,LinkedList代碼在「標題」對象中使用空指針來指定列表的末尾。這個額外的指針稍慢一些,因爲你必須追趕它來獲得「有效載荷」。但它允許多態性(4段落)。
我們通常根本不會想到List實現的細節。我們編碼到「List」界面。 List允許我們插入和刪除指向對象的指針,並通過索引訪問這些指向對象的指針。指針可以爲空。
LinkedList快速插入/刪除,但隨機訪問速度較慢(它必須追逐「標頭」指針)。 ArrayList隨機訪問很快,但插入/移除速度慢(它必須複製內存)。您將代碼寫入「List」接口並根據您的使用選擇實現。而且您可以稍後更改實現,而無需更改使用List接口的代碼。
注意在C++標準模板庫中,std::list<std::string>
自己創建一個對象集合(不是指向對象的指針),並且不能插入空值。類似Java的集合將是一個std::list<std::string *>
,它是可以爲空的指針集合。
收集「指針」具有允許多態性的優點。如果我收集對象而不是指針,那麼我不能將一個SuperString放入字符串集合中,因爲代碼實際上是將結構複製到它自己的內存中。 SuperString對於一個String插槽來說太大了。但指針都是一樣的大小;我可以把一個指向SuperString的指針放入String指針集合中。
元素不指向任何東西。包含元素的節點指向下一個節點(可能還有前一個節點)。 –