生活随笔
收集整理的這篇文章主要介紹了
java中ArrayList与LinkedList的区别
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
一、背景
面試題中經常會被面試官問到ArrayList和LinkedList的區別,下面從源碼角度來對他們進行一下簡單的闡述,相信會對它們有一個更全面深入的了解。
首先,ArrayList和LinkedList都實現了List接口,ArrayList的底層是通過【動態數組】實現的,LinkedList底層是通過【鏈表】實現的。
二、ArrayList
1、通過add(e)方法添加元素 java中的數組一旦定義之后長度length就不可變了,是不可變數組;而python是可變數組,這點需要注意這兩種語言的不同;ArrayList可以不斷的通過add添加元素,它的size也是變化的,數組的長度又是不可變的,而ArrayList的底層是數組,它們不就矛盾了嗎?別急,ArrayList是通過判斷當前集合中元素的size數與數組的長度比較,如果size>數組length,再對數組擴容,然后將元素賦值給擴容后的數組 下面是截取的ArrayList類中的關于add方法的代碼
private static final int DEFAULT_CAPACITY
= 10 ;
private static final Object [ ] EMPTY_ELEMENTDATA
= { } ;
private static final Object [ ] DEFAULTCAPACITY_EMPTY_ELEMENTDATA
= { } ;
transient Object [ ] elementData
;
private int size
;
public ArrayList ( ) { this . elementData
= DEFAULTCAPACITY_EMPTY_ELEMENTDATA
;
}
public boolean add ( E e
) { ensureCapacityInternal ( size
+ 1 ) ; elementData
[ size
++ ] = e
; return true ;
}
private void ensureCapacityInternal ( int minCapacity
) { ensureExplicitCapacity ( calculateCapacity ( elementData
, minCapacity
) ) ;
}
private static int calculateCapacity ( Object [ ] elementData
, int minCapacity
) { if ( elementData
== DEFAULTCAPACITY_EMPTY_ELEMENTDATA
) { return Math . max ( DEFAULT_CAPACITY
, minCapacity
) ; } return minCapacity
;
}
private void ensureExplicitCapacity ( int minCapacity
) { modCount
++ ; if ( minCapacity
- elementData
. length
> 0 ) grow ( minCapacity
) ;
}
private void grow ( int minCapacity
) { int oldCapacity
= elementData
. length
; int newCapacity
= oldCapacity
+ ( oldCapacity
>> 1 ) ; if ( newCapacity
- minCapacity
< 0 ) newCapacity
= minCapacity
; if ( newCapacity
- MAX_ARRAY_SIZE
> 0 ) newCapacity
= hugeCapacity ( minCapacity
) ; elementData
= Arrays . copyOf ( elementData
, newCapacity
) ;
}
總結一下:通過add(e)方法在集合尾部添加數據,效率還是比較高的,因為不涉及數組元素的復制移動,但有時涉及到擴容 2、通過get(index)根據索引獲取元素對象 下面是ArrayList類中的關于get(index)方法的代碼
public E get ( int index
) { rangeCheck ( index
) ; return elementData ( index
) ; }
E elementData ( int index
) { return ( E ) elementData
[ index
] ; }
總結一下:get(index)不需要遍歷,直接取出相應下標的數組元素,效率較高。 3、通過add(index,e)指定位置添加元素 下面是ArrayList類中的關于add(index,e)方法的源代碼
public void add ( int index
, E element
) { rangeCheckForAdd ( index
) ; ensureCapacityInternal ( size
+ 1 ) ; System . arraycopy ( elementData
, index
, elementData
, index
+ 1 , size
- index
) ; elementData
[ index
] = element
; size
++ ; }
原理圖如下: 總結一下:add(index,e)方法涉及到元素的整體復制向后移動,元素下標也會發生變化,此種方式添加元素效率較低,數組容量不足,也會進行擴容。
4、remove(index)刪除元素源碼
public E remove ( int index
) { rangeCheck ( index
) ; modCount
++ ; E oldValue
= elementData ( index
) ; int numMoved
= size
- index
- 1 ; if ( numMoved
> 0 ) System . arraycopy ( elementData
, index
+ 1 , elementData
, index
, numMoved
) ; elementData
[ -- size
] = null ; return oldValue
; }
總結一下:remove(index)刪除元素,會導致剩下的元素整體復制移動,元素下標會發生變化,因此該方式刪除元素數據效率較低。
二、LinkedList
1、通過add(e)方法添加元素 以下是LinkedList類中部分源碼。
. . . . . . 省略
. . . . . . transient int size
= 0 ; transient Node < E > first
; transient Node < E > last
; public LinkedList ( ) { } public boolean add ( E e
) { linkLast ( e
) ; return true ; } void linkLast ( E e
) { final Node < E > l
= last
; final Node < E > newNode
= new Node < > ( l
, e
, null ) ; last
= newNode
; if ( l
== null ) first
= newNode
; else l
. next
= newNode
; size
++ ; modCount
++ ; } 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
; } }
LinkedList對象結構示意圖:
總結一下:LinkedList對象中通過add()方法添加元素時,對已經存在的元素沒有影響,沒有對其他元素的復制移動等操作,效率高
2、通過add(index,e)添加元素到指定位置 以下是相關的源碼,關鍵代碼做了注釋。
public void add ( int index
, E element
) { checkPositionIndex ( index
) ; if ( index
== size
) linkLast ( element
) ; else linkBefore ( element
, node ( index
) ) ; } void linkBefore ( E e
, Node < E > succ
) { final Node < E > pred
= succ
. prev
; final Node < E > newNode
= new Node < > ( pred
, e
, succ
) ; succ
. prev
= newNode
; if ( pred
== null ) first
= newNode
; else pred
. next
= newNode
; size
++ ; modCount
++ ; } Node < E > node ( int index
) { if ( index
< ( size
>> 1 ) ) { Node < E > x
= first
; for ( int i
= 0 ; i
< index
; i
++ ) x
= x
. next
; return x
; } else { Node < E > x
= last
; for ( int i
= size
- 1 ; i
> index
; i
-- ) x
= x
. prev
; return x
; } }
總結一下:add(index,e)方法添加元素到集合中的指定位置,只是改變了上一個節點和下一個節點的指向位置,其他元素不受影響,所以比ArrayList的add(index,e)的效率要高,但需注意在查找index節點時,進行了遍歷,如果size比較大的話,遍歷會比較耗時。
3、通過remove(index)的方法刪除元素。 以下是LinkedList中相關源碼,關鍵代碼做了注釋
public E remove ( int index
) { checkElementIndex ( index
) ; return unlink ( node ( index
) ) ; } Node < E > node ( int index
) { if ( index
< ( size
>> 1 ) ) { Node < E > x
= first
; for ( int i
= 0 ; i
< index
; i
++ ) x
= x
. next
; return x
; } else { Node < E > x
= last
; for ( int i
= size
- 1 ; i
> index
; i
-- ) x
= x
. prev
; return x
; } } E unlink ( Node < E > x
) { final E element
= x
. item
; final Node < E > next
= x
. next
; final Node < E > prev
= x
. prev
; if ( prev
== null ) { first
= next
; } else { prev
. next
= next
; x
. prev
= null ; } if ( next
== null ) { last
= prev
; } else { next
. prev
= prev
; x
. next
= null ; } x
. item
= null ; size
-- ; modCount
++ ; return element
; }
總結一下:remove(index)方法刪除集合中的元素只是改變了上一個節點和下一個節點的指向位置,對其他元素沒有造成影響,效率比較高,但需注意在查找index節點時,進行了遍歷,如果size比較大的話,遍歷會比較耗時
4、通過get(index)獲取集合中的元素 以下是LinkedList中的部分源碼,關鍵部分做了注釋。
public E get ( int index
) { checkElementIndex ( index
) ; return node ( index
) . item
; } Node < E > node ( int index
) { if ( index
< ( size
>> 1 ) ) { Node < E > x
= first
; for ( int i
= 0 ; i
< index
; i
++ ) x
= x
. next
; return x
; } else { Node < E > x
= last
; for ( int i
= size
- 1 ; i
> index
; i
-- ) x
= x
. prev
; return x
; } }
總結一下:LinkedList的get(index)方法通過遍歷查詢元素,效率比較低;而ArrayList中的get(index)直接通過下標獲取數組元素,不用遍歷,效率更高。
總結
以上是生活随笔 為你收集整理的java中ArrayList与LinkedList的区别 的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔 網站內容還不錯,歡迎將生活随笔 推薦給好友。