結合上面代碼中的注釋及雙向循環鏈表的知識,應該很容易理解LinkedList構造方法所涉及的內容。下面開始分析LinkedList的其他方法。
add(E e)
1 public boolean add(E e) {
2 addBefore(e, header);
3 return true;
4 }
從上面的代碼可以看出,add(E e)方法只是調用了addBefore(E e,Entry《E》 entry)方法,并且返回true。
addBefore(E e,Entry《E》 entry)
1 private Entry《E》 addBefore(E e, Entry《E》 entry) {
2 Entry《E》 newEntry = new Entry《E》(e, entry, entry.previous);
3 newEntry.previous.next = newEntry;
4 newEntry.next.previous = newEntry;
5 size++;
6 modCount++;
7 return newEntry;
8 }
addBefore(E e,Entry《E》 entry)方法是個私有方法,所以無法在外部程序中調用(當然,這是一般情況,你可以通過反射上面的還是能調用到的)。
addBefore(E e,Entry《E》 entry)先通過Entry的構造方法創建e的節點newEntry(包含了將其下一個節點設置為entry,上一個節點設置為entry.previous的操作,相當于修改newEntry的“指針”),之后修改插入位置后newEntry的前一節點的next引用和后一節點的previous引用,使鏈表節點間的引用關系保持正確。之后修改和size大小和記錄modCount,然后返回新插入的節點。
總結,addBefore(E e,Entry《E》 entry)實現在entry之前插入由e構造的新節點。而add(E e)實現在header節點之前插入由e構造的新節點。
add(int index,E e)
1 public void add(int index, E element) {
2 addBefore(element, (index==size ? header : entry(index)));
3 }
也是調用了addBefore(E e,Entry《E》 entry)方法,只是entry節點由index的值決定。
構造方法,addAll(Collection《? extends E》 c),add(E e),addBefor(E e,Entry《E》 entry)方法可以構造鏈表并在指定位置插入節點,為了便于理解,下面給出插入節點的示意圖。
addFirst(E e)
1 public void addFirst(E e) {
2 addBefore(e, header.next);
3 }
addLast(E e)
1 public void addLast(E e) {
2 addBefore(e, header);
3 }
看上面的示意圖,結合addBefore(E e,Entry《E》 entry)方法,很容易理解addFrist(E e)只需實現在header元素的下一個元素之前插入,即示意圖中的一號之前。addLast(E e)只需在實現在header節點前(因為是循環鏈表,所以header的前一個節點就是鏈表的最后一個節點)插入節點(插入后在2號節點之后)。
clear()
1 public void clear() {
2 Entry《E》 e = header.next;
3 // e可以理解為一個移動的“指針”,因為是循環鏈表,所以回到header的時候說明已經沒有節點了
4 while (e != header) {
5 // 保留e的下一個節點的引用
6 Entry《E》 next = e.next;
7 // 接觸節點e對前后節點的引用
8 e.next = e.previous = null;
9 // 將節點e的內容置空
10 e.element = null;
11 // 將e移動到下一個節點
12 e = next;
13 }
14 // 將header構造成一個循環鏈表,同構造方法構造一個空的LinkedList
15 header.next = header.previous = header;
16 // 修改size
17 size = 0;
18 modCount++;
19 }
上面代碼中的注釋已經足以解釋這段代碼的邏輯,需要注意的是提到的“指針”僅僅是概念上的類比,Java并不存在“指針”的概念,而只有引用,為了便于理解所以部分說明使用了“指針”。
contains(Object o)
1 public boolean contains(Object o) {
2 return indexOf(o) != -1;
3 }
僅僅只是判斷o在鏈表中的索引。先看indexOf(Object o)方法。
1 public int indexOf(Object o) {
2 int index = 0;
3 if (o==null) {
4 for (Entry e = header.next; e != header; e = e.next) {
5 if (e.element==null)
6 return index;
7 index++;
8 }
9 } else {
10 for (Entry e = header.next; e != header; e = e.next) {
11 if (o.equals(e.element))
12 return index;
13 index++;
14 }
15 }
16 return -1;
17 }
indexOf(Object o)判斷o鏈表中是否存在節點的element和o相等,若相等則返回該節點在鏈表中的索引位置,若不存在則放回-1。
contains(Object o)方法通過判斷indexOf(Object o)方法返回的值是否是-1來判斷鏈表中是否包含對象o。
element()
1 public E element() {
2 return getFirst();
3 }
getFirst()
1 public E getFirst() {
2 if (size==0)
3 throw new NoSuchElementException();
4 return header.next.element;
5 }
element()方法調用了getFirst()返回鏈表的第一個節點的元素。為什么要提供功能一樣的兩個方法,像是包裝了一下名字?其實這只是為了在不同的上下文“語境”中能通過更貼切的方法名調用罷了。
get(int index)
1 public E get(int index) {
2 return entry(index).element;
3 }
get(int index)方法用于獲得指定索引位置的節點的元素。它通過entry(int index)方法獲取節點。entry(int index)方法遍歷鏈表并獲取節點,在上面有說明過,不再陳述。
set(int index,E element)
1 public E set(int index, E element) {
2 Entry《E》 e = entry(index);
3 E oldVal = e.element;
4 e.element = element;
5 return oldVal;
6 }
評論