<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                關注點 | 結論 ---|--- ArrayList是否允許空 | 允許 ArrayList是否允許重復數據 | 允許 ArrayList是否有序 | 有序 ArrayList是否線程安全 | 非線程安全 #### 1. 繼承的父類和實現的接口 ```java public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable ``` > ArrayList 繼承了 AbstractList 類,此類提供了 List 接口的骨干實現,繼承此類的子類適合用于“隨機訪問”數據存儲(如數組),Vector 也是此類的子類。 > 與 AbstractList 類對應的類是 AbstractSequentialList 類,繼承該類的子類適合用于“連續訪問”數據存儲(如鏈接列表),代表的子類如 LinkedList 。 > ArrayList 實現了 List 接口,List 接口通常表示一個列表(數組、隊列、鏈表、棧等),其中的元素可以重復,代表的實現類有 ArrayList、LinkedList、Stack、Vector。 > ArrayList 實現了 RandomAccess 接口,該接口為標記接口,用來表明其支持快速隨機訪問。 > ArrayList 實現了 Cloneable 接口,以指示 Object.clone() 方法可以合法地對該類實例進行按字段復制。 > ArrayList 實現了 Serializable 接口,因此它支持序列化,能夠通過序列化傳輸。 #### 2. 屬性 ```java /** * 序列版本號 */ private static final long serialVersionUID = 8683452581122892189L; /** * 默認容量 */ private static final int DEFAULT_CAPACITY = 10; /** * 無參的空數組常量 */ private static final Object[] EMPTY_ELEMENTDATA = {}; /** * 有參的空數組 */ private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}; /** * 存放元素的數組,從這可以發現ArrayList的底層實現就是一個Object數組 */ transient Object[] elementData; /** * 當前的實際元素個數 */ private int size; ``` #### 3. 構造函數 ```java //用初始容量作為參數的構造方法 public ArrayList(int initialCapacity) { if (initialCapacity > 0) { //初始容量大于0,實例化數組 this.elementData = new Object[initialCapacity]; } else if (initialCapacity == 0) { //初始容量等于0,賦予空數組 this.elementData = EMPTY_ELEMENTDATA; } else { throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity); } } //無參的構造方法 public ArrayList() { this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; } ``` > 從構造方法中我們可以看見,默認情況下,elementData是一個大小為0的空數組,當我們指定了初始大小的時候,elementData的初始大小就變成了我們所指定的初始大小了。 #### 4. get,set方法 ```java //返回指定索引的值 public E get(int index) { //檢查索引值是否越界 rangeCheck(index); return elementData(index); } private void rangeCheck(int index) { if (index >= size) throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); } @SuppressWarnings("unchecked") E elementData(int index) { return (E) elementData[index]; } //將制定索引上的值替換為新值,并返回舊值 public E set(int index, E element) { rangeCheck(index); E oldValue = elementData(index); elementData[index] = element; return oldValue; } ``` > 因為ArrayList是采用數組結構來存儲的,所以它的get方法非常簡單,先是判斷一下有沒有越界,之后就可以直接通過數組下標來獲取元素了,所以get的時間復雜度是O(1)。 > set方法的作用是把下標為index的元素替換成element,跟get非常類似,所以就不在贅述了,時間復雜度度為O(1)。 #### 5. add ```java //將指定的元素添加到列表的尾部 public boolean add(E e) { //動態數組 ensureCapacityInternal(size + 1); // Increments modCount!! elementData[size++] = e; return true; } private void ensureCapacityInternal(int minCapacity) { if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity); } ensureExplicitCapacity(minCapacity); } private void ensureExplicitCapacity(int minCapacity) { modCount++; // overflow-conscious code if (minCapacity - elementData.length > 0) grow(minCapacity); } private void grow(int minCapacity) { // overflow-conscious code int oldCapacity = elementData.length; //默認是擴大為原來的1.5倍 int newCapacity = oldCapacity + (oldCapacity >> 1); //1.5倍還是不夠的話,直接用傳進來的minCapacity作為容量值 if (newCapacity - minCapacity < 0) newCapacity = minCapacity; //自己傳進來的值minCapacity溢出的處理 if (newCapacity - MAX_ARRAY_SIZE > 0) newCapacity = hugeCapacity(minCapacity); // minCapacity is usually close to size, so this is a win: //拷貝數據到新的擴容后數組中 elementData = Arrays.copyOf(elementData, newCapacity); } private static int hugeCapacity(int minCapacity) { if (minCapacity < 0) // overflow throw new OutOfMemoryError(); return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE; } //將元素添加到指定位置 public void add(int index, E element) { rangeCheckForAdd(index); ensureCapacityInternal(size + 1); // Increments modCount!! //arraycopy(被復制的數組,從第幾個元素開始復制,要復制到的數組,從第幾個元素開始粘貼,一共需要復制的元素個數) System.arraycopy(elementData, index, elementData, index + 1, size - index); elementData[index] = element; size++; } ``` > ArrayList的add方法也很好理解,在插入元素之前,它會先檢查是否需要擴容,然后再把元素添加到數組中最后一個元素的后面。在ensureCapacityInternal方法中,我們可以看見,如果當elementData為空數組時,它會使用默認的大小去擴容。所以說,通過無參構造方法來創建ArrayList時,它的大小其實是為0的,只有在使用到的時候,才會通過grow方法去創建一個大小為10的數組。 > 第一個add方法的復雜度為O(1),雖然有時候會涉及到擴容的操作,但是擴容的次數是非常少的,所以這一部分的時間可以忽略不計。如果使用的是帶指定下標的add方法,則復雜度為O(n),因為涉及到對數組中元素的移動,這一操作是非常耗時的 > grow方法是在數組進行擴容的時候用到的,從中我們可以看見,ArrayList每次擴容都是擴1.5倍,然后調用Arrays類的copyOf方法,把元素重新拷貝到一個新的數組中去。 #### 6. remove ```java public E remove(int index) { rangeCheck(index); modCount++; E oldValue = elementData(index); int numMoved = size - index - 1; if (numMoved > 0) //arraycopy(被復制的數組,從第幾個元素開始復制,要復制到的數組,從第幾個元素開始粘貼,一共需要復制的元素個數) System.arraycopy(elementData, index+1, elementData, index, numMoved); elementData[--size] = null; // clear to let GC do its work return oldValue; } ``` > remove方法與add帶指定下標的方法非常類似,也是調用系統的arraycopy方法來移動元素,時間復雜度為O(n)。 #### 7. size(),isEmpty() ```java public int size() { return size; } public boolean isEmpty() { return size == 0; } ``` > size方法非常簡單,它是直接返回size的值,也就是返回數組中元素的個數,時間復雜度為O(1)。這里要注意一下,返回的并不是數組的實際大小。 #### 8.indexOf()和lastIndexOf() ```java public int indexOf(Object o) { if (o == null) { for (int i = 0; i < size; i++) if (elementData[i]==null) return i; } else { for (int i = 0; i < size; i++) if (o.equals(elementData[i])) return i; } return -1; } public int lastIndexOf(Object o) { if (o == null) { for (int i = size-1; i >= 0; i--) if (elementData[i]==null) return i; } else { for (int i = size-1; i >= 0; i--) if (o.equals(elementData[i])) return i; } return -1; } ``` > indexOf方法的作用是返回第一個等于給定元素的值的下標。它是通過遍歷比較數組中每個元素的值來查找的,所以它的時間復雜度是O(n)。 > lastIndexOf的原理跟indexOf一樣,而它僅僅是從后往前找起罷了。 #### 9. removeRange() ```java //刪除fromIndex到toIndex之間的全部元素 protected void removeRange(int fromIndex, int toIndex) { modCount++; //numMoved為刪除索引后面的元素個數 int numMoved = size - toIndex; //將刪除索引后面的元素復制到以fromIndex為起始位置的存儲空間中去 System.arraycopy(elementData, toIndex, elementData, fromIndex,numMoved); int newSize = size - (toIndex-fromIndex); //將ArrayList后面(toIndex-fromIndex)個元素置為null for (int i = newSize; i < size; i++) { elementData[i] = null; } size = newSize; } ``` #### 10. Vector > vector因為很多方法都跟ArrayList一樣,只是多加了個synchronized來保證線程安全罷了。如果照著ArrayList的方式再將一次就顯得沒意思了,所以只把Vector與ArrayList的不同點提一下就可以了。 Vector比ArrayList多了一個屬性: > protected int capacityIncrement; 這個屬性是在擴容的時候用到的,它表示每次擴容只擴capacityIncrement個空間就足夠了。該屬性可以通過構造方法給它賦值。先來看一下構造方法: ```java public Vector(int initialCapacity, int capacityIncrement) { super(); if (initialCapacity < 0) throw new IllegalArgumentException("Illegal Capacity: "+initialCapacity); this.elementData = new Object[initialCapacity]; this.capacityIncrement = capacityIncrement; } public Vector(int initialCapacity) { this(initialCapacity, 0); } public Vector() { this(10); } ``` 從構造方法中,我們可以看出Vector的默認大小也是10,而且它在初始化的時候就已經創建了數組了,這點跟ArrayList不一樣。再來看一下grow方法: ```java private void grow(int minCapacity) { // overflow-conscious code int oldCapacity = elementData.length; int newCapacity = oldCapacity + ((capacityIncrement > 0) ? capacityIncrement : oldCapacity); if (newCapacity - minCapacity < 0) newCapacity = minCapacity; if (newCapacity - MAX_ARRAY_SIZE > 0) newCapacity = hugeCapacity(minCapacity); elementData = Arrays.copyOf(elementData, newCapacity); } ``` 從grow方法中我們可以發現,newCapacity默認情況下是兩倍的oldCapacity,而當指定了capacityIncrement的值之后,newCapacity變成了oldCapacity+capacityIncrement。 #### 10. 總結 > 注意擴充容量的方法ensureCapacity。ArrayList在每次增加元素(可能是1個,也可能是一組)時,都要調用該方法來確保足夠的容量。當容量不足以容納當前的元素個數時,就設置新的容量為舊的容量的1.5倍,如果設置后的新容量還不夠,則直接新容量設置為傳入的參數(也就是所需的容量),而后用Arrays.copyof()方法將元素拷貝到新的數組(詳見下面的第3點)。從中可以看出,當容量不夠時,每次增加元素,都要將原來的元素拷貝到一個新的數組中,非常之耗時,也因此建議在事先能確定元素數量的情況下,才使用ArrayList,否則建議使用LinkedList。 > 1、ArrayList創建時的大小為0;當加入第一個元素時,進行第一次擴容時,默認容量大小為10。 > 2、ArrayList每次擴容都以當前數組大小的1.5倍去擴容。 > 3、Vector創建時的默認大小為10。 > 4、Vector每次擴容都以當前數組大小的2倍去擴容。當指定了capacityIncrement之后,每次擴容僅在原先基礎上增加capacityIncrement個單位空間。 > 5、ArrayList和Vector的add、get、size方法的復雜度都為O(1),remove方法的復雜度為O(n)。 > 6、ArrayList是非線程安全的,Vector是線程安全的。 > 7. ArrayList不是線程同步的,在多線程下可以考慮使用 Collections.synchronizedList 方法將該列表“包裝”起來。這最好在創建時完成,以防止意外對列表進行不同步的訪問:代碼如下: ```java List list = Collections.synchronizedList(new ArrayList(...)); ```
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看