ArrayList 類(一)

PS:若是以爲文章有什麼地方寫錯了,哪裏寫得很差,或者有什麼建議,歡迎指點。

ArrayList 類提供了 List ADT 的可增加數組的實現。java

1、自定義實現的 ArrayList 類 MyArrayList

源碼連接:戳此進GitHub查看git

MyArrayList 泛型類實現了 Iterable 接口從而能夠擁有加強 for 循環(for each 循環)。github

public class MyArrayList<AnyType> implements Iterable<AnyType> {
     
    @Override
    public Iterator<AnyType> iterator() {
        return new ArrayListIterator();
    }   
}

1. 類屬性

MyArrayList 是基於數組實現的,其屬性有:算法

private static final int DEFAULT_CAPACITY = 10;

private int theSize;

private AnyType[] theArrays;

其中常量 DEFAULT_CAPACITY 表示數組的基礎容量。theSize 表示數組表當前長度(數組元素個數),做索引時,A[theSize - 1] 表示數組的最後一個元素,而 A[theSize] 表示新添加的項能夠被放置的位置。泛型數組 theArrays 爲 MyArrayList 類的數組實現,即對 MyArrayList 對象的操做實際爲對數組 theArrays 的操做。編程

2. 構造方法

當實例化 MyArrayList 對象時,調用構造方法:數組

public MyArrayList(){
    theArrays = (AnyType[])new Object[DEFAULT_CAPACITY]; 
    doClear();
 }

在構造方法中先實例化泛型數組 theArrays。因爲泛型數組的建立是非法的,因此咱們須要建立一個泛型類型限界的數組;即建立一個 Object[] 類型的數組,而後向泛型類型數組 AnyType[] 強制轉型。ide

而後調用 doClear() 方法對數組表進行清空、初始化的操做,此方法僅類內部可調用:this

private void doClear(){
   theSize = 0;
   expandCapacity(DEFAULT_CAPACITY);
}

此處先設置 theSize = 0,而後調用 expandCapacity() 方法改變數組容量爲基礎容量。(在 expandCapacity() 方法的實現中,若擴充的容量(參數)小於 theSize 時表示非法的操做。)code

3. 成員方法

數組擴容方法 expandCapacity() :對象

public void expandCapacity(int newCapacity){
    if (newCapacity < theSize){
        return;
    }

   // 數組容量的擴充:
   AnyType[] newArrays = (AnyType[])new Object[newCapacity];
 
   // 利用 System.arraycopy() 方法拷貝數組
   System.arraycopy(theArrays,0,newArrays,0,theSize);
   theArrays = newArrays;
}
System.arraycopy() 方法:
public static native void arraycopy(Object src, int srcPos, Object dest, int destPos, int length);

get 方法的實現

/**
 * 根據下標獲得數組元素的值
 */
public AnyType get(int idx){
    if (idx <0 || idx >= theSize){
        throw new ArrayIndexOutOfBoundsException();
    }
    return theArrays[idx];
}

set 方法的實現

/**
 * 根據下標設置數組元素的值
 * 返回該下標元素的原值
 */
public AnyType set(int idx,AnyType newVal){
    if (idx <0 || idx >= theSize){
        throw new ArrayIndexOutOfBoundsException();
    }

    AnyType oldVal = theArrays[idx];
    theArrays[idx] = newVal;
    return oldVal;
}

add 方法的實現

/**
  * 根據下標向數組插入新元素 
  */
public boolean add(int idx,AnyType newVal){
    // 當 idx=theSize 時,在 A[theSize] 位置處插入元素
    if (idx < 0 || idx > theSize){
        throw new ArrayIndexOutOfBoundsException();
    }

    // 數組滿時擴充容量
    if (theArrays.length == theSize){
        expandCapacity(theSize*2 + 1);
    }

    // 數組元素後移
    for (int i=theSize;i>idx;i--){
        theArrays[i] = theArrays[i-1];
    }

    theArrays[idx] = newVal;
    theSize++;
    return true;
}

/**
 * 在數組末尾插入新元素
 */
public boolean add(AnyType newVal){
    add(theSize,newVal);
    return true;
}

remove 方法的實現

/**
 * 根據下標刪除元素
 * 返回被刪除的元素
 */
public AnyType remove(int idx){
    if (idx < 0 || idx >= theSize){
        throw new ArrayIndexOutOfBoundsException();
    }

    // 數組元素前移
    AnyType removedElem = theArrays[idx];
    for (int i = idx; i < theSize-1; i++) {
        theArrays[i] = theArrays[i+1];
    }
    theSize--;
    return removedElem;
}

4. Iterator 迭代器

關於 Iterator 接口

實現 Iterable 接口的集合必須提供 iterator 方法,該方法返回一個 Iterator (java.util.Iterator)類型的對象:

public interface Iterator<AnyType> {
    boolean hasNext();
    AnyType next();
    void remove();
}

即每一個集合都可經過 iterator 方法建立並返回給客戶一個實現 Iterator 接口的對象,並把 當前位置 的概念在對象內部存儲下來。根據當前位置項每次調用 hasNext() 來判斷是否存在下一項,調用 next() 來給出下一項,而 remove() 方法則刪除由 next() 方法最新返回的項(即當調用一次 remove() 後,直到對 next() 再調用一次後才能調用 remove() 方法)。例:

public static <AnyType> void print(Collection<AnyType> coll){
    Iterator<AnyType> itr = coll.iterator();
    while(itr.hasNext()){
        AnyType item = itr.next();
        System.out.println(item);
        // itr.remove();
    }
}

Java 中的加強 for 循環(for each)底層便是經過這種迭代器模式來實現的,當使用加強 for 循環時也就是間接的使用 Iterator。

MyArrayList 中 Iterator 的實現

import java.util.Iterator;
import java.util.NoSuchElementException;

public class MyArrayList<AnyType> implements Iterable<AnyType> {
    ......

    @Override
    public Iterator<AnyType> iterator() {
        return new ArrayListIterator();
    }

    private class ArrayListIterator implements Iterator<AnyType>{

        // 初始時當前位置爲 0
        private int current = 0;
        
        @Override
        public boolean hasNext() {
            return current < theSize;
        }

        @Override
        public AnyType next() {
            if (!hasNext()){
                throw new NoSuchElementException();
            }
            return theArrays[current++];
        }

        @Override
        public void remove() {
            /* 由於 remove() 方法有相同的,MyArrayList.this 表示外部類當前對象的一個引用 */
            MyArrayList.this.remove(--current);
        }
    }
}

iterator() 方法直接返回 ArrayListIterator 類的一個實例,該類是一個實現 Iterator 接口的類。ArrayListIterator 存儲當前位置的概念,並提供 hasNext()、next()、remove() 的實現。當前位置 表示要被查看的下一元素(的數組下標),所以初始化當前位置爲 0。

其中,泛型類 ArrayListIterator 是一個 內部類,使用內部類的目的及優勢:

  1. next() 方法中使用當前位置做爲下標訪問數組元素而後將當前位置向後推動,而迭代器中是沒有數組的,使用內部類能夠訪問外部類的域 theArrays;
  2. theArrays 是 MyArrayList 的私有域,使用內部類訪問能夠很好的知足面向對象編程的基本原則,即讓數據儘量地隱藏;
  3. 知足迭代器 Iterator 的特性,即當集合(外部類)不存在的時候,迭代器(內部類)也是不存在的。

2、MyArrayList 類各方法的算法分析

由於 ArrayList 是基於數組實現的,因此和數組類似:ArrayList 的 get() 和 set() 方法花費常數時間 O(1);而使用 add() 和 remove() 方法時爲了保持內存數據的連續性,須要作大量的數據搬移工做,其花費的時間代價爲 O(n)。


歡迎您的點贊、收藏和評論!(完)

相關文章
相關標籤/搜索