[ソース]のJavaコレクションクラス-ArrayList

まず、クラスの継承関係

public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable

ArrayListのAbstractList連続、およびランダム・リストも(インターフェイスがマークされている空のインターフェイスを、。)を達成、Cloneableを(クローン化されてもよい)、直列化インターフェース。

第二に、クラス属性

    //默认容量
    private static final int DEFAULT_CAPACITY = 10;

    //空对象数组(initialCapacity == 0时返回)
    private static final Object[] EMPTY_ELEMENTDATA = {};

    //调用无参构造方法,返回的是该数组
    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

    //元素数组,保存添加到ArrayList中的元素
    transient Object[] elementData;
    
    //ArrayList大小
    private int size;

elementData過渡が変更され、それはからelementDataシリアライズすることはできません。ArrayListのをシリアル化することが可能ですが、これはなぜですか?

  • シリアル化および逆シリアル化するには2つの方法のArrayListのwriteObject、readObjectメソッドがありますので。elementDataが過渡ArrayListの拡大を避けるために変更された(1.5)スペースの浪費につながります
  1. データはObjectOutputStreamのに書かれているシリアル化からelementData
private void writeObject(java.io.ObjectOutputStream s)
        throws java.io.IOException{
        // Write out element count, and any hidden stuff
        int expectedModCount = modCount;
        s.defaultWriteObject();

        // Write out size as capacity for behavioural compatibility with clone()
        s.writeInt(size);

        // Write out all elements in the proper order.
        for (int i=0; i<size; i++) {
            s.writeObject(elementData[i]);
        }

        if (modCount != expectedModCount) {
            throw new ConcurrentModificationException();
        }
    }
  1. デシリアライズ時間はObjectInputStreamのから読み込まれます
private void readObject(java.io.ObjectInputStream s)
        throws java.io.IOException, ClassNotFoundException {
        elementData = EMPTY_ELEMENTDATA;

        // Read in size, and any hidden stuff
        s.defaultReadObject();

        // Read in capacity
        s.readInt(); // ignored

        if (size > 0) {
            // be like clone(), allocate array based upon size not capacity
            ensureCapacityInternal(size);

            Object[] a = elementData;
            // Read in all elements in the proper order.
            for (int i=0; i<size; i++) {
                a[i] = s.readObject();
            }
        }
    }

第三に、コンストラクタ

  • 指定された容量
    public ArrayList(int initialCapacity) {
        if (initialCapacity > 0) {
            this.elementData = new Object[initialCapacity];
        } else if (initialCapacity == 0) {
            //空对象数组
            this.elementData = EMPTY_ELEMENTDATA;
        } else {
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        }
    }
  • デフォルト
    public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }
  • ArrayListを(コレクション<?拡張E> C)
    public ArrayList(Collection<? extends E> c) {
        elementData = c.toArray();
        if ((size = elementData.length) != 0) {
            if (elementData.getClass() != Object[].class)
                elementData = Arrays.copyOf(elementData, size, Object[].class);
        } else {
            //空对象数组
            this.elementData = EMPTY_ELEMENTDATA;
        }
    }

四、ArrayListにどのように拡張

    public boolean add(E e) {
        //确保elementData数组的大小
        ensureCapacityInternal(size + 1);
        //在结尾处添加元素
        elementData[size++] = e;
        return true;
    }

上記添加元素がensureCapacityInternal(サイズ+ 1)と呼ぶことにする前に、ソースは、方法の(E eを)追加され、アレイからelementDataのサイズことを確実にするために。

    private void ensureCapacityInternal(int minCapacity) {
        // 判断元素数组是否为空数组
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            //minCapacity最少=DEFAULT_CAPACITY=10
            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
        }

        ensureExplicitCapacity(minCapacity);
    }
  • ensureCapacityInternal源からelementData断片を第一の基準は、もしそうであれば、Math.max非空の配列コンストラクタであるか否かが判定される()が大きい値はminCapacityになるように割り当てられているかかり、最小値は10(初期容量)です。その後、ensureExplicitCapacityを呼び出します。
    private void ensureExplicitCapacity(int minCapacity) {
        // List结构性修改加1
        modCount++;
        //minCapacity大于elementData数组长度
        if (minCapacity - elementData.length > 0)
            //增长
            grow(minCapacity);
    }
  • 構造変化のリストのmodCountレコード番号でensureExplicitCapacity(反復中の構造変化は、誤った結果を引き起こす場合があります)。
  • 次に、もしminCapacityにからelementDataを増やすと呼ばれる配列の長さよりも大きい(minCapacityに)成長関数
    
    private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
        //oldCapacity >> 1右移一位,这里相当于扩容1.5倍
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        if (newCapacity - minCapacity < 0)
            newCapacity = 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);
    }

上記膨張処理oldCapacity >> 1つの表示elementData.length右一つは、拡張後の容量維持率は1.5倍の体積であります

第五に、主な機能

()関数を削除
    public E remove(int index) {
        rangeCheck(index);

        modCount++;
        E oldValue = elementData(index);
        //需要移动的元素个数
        int numMoved = size - index - 1;
        //删除的不是最后一个元素
        if (numMoved > 0)
            //index后的元素都向前移动一位
            System.arraycopy(elementData, index+1, elementData, index, numMoved);
        //size减一,释放引用,方便垃圾回收器进行垃圾回收
        elementData[--size] = null; // clear to let GC do its work

        return oldValue;
    }
  • 要素の数は、インデックス要素が1つ前に移動した後(INT指標)の算出方法は、最初の参照を解放するためにnullに割り当てられたサイズから1を引いた、便利なガベージコレクタ次いで、(移動するSystem.arraycopyの道を呼び出す)、移動する必要があります削除しますガベージコレクション。

    シングルスレッド環境下では、要素を削除する権利を、あなたはイテレータを()を使用するイテレータの要素を削除する必要があります。

たとえば、コレクション「A」を削除するには

        Iterator<String> iterator = list.iterator();
        while (iterator.hasNext()){
            if ("a".equals(iterator.next())) {
                iterator.remove();
            }
        }

またはラムダ式を使用します

list.removeIf("x"::equals);
セット()関数は、新しい値に置き換えて、以前の値を返します。
    public E set(int index, E element) {
        //检查索引
        rangeCheck(index);

        E oldValue = elementData(index);
        elementData[index] = element;
        //返回旧值
        return oldValue;
    }
要素を取得するために、()関数を取得
    public E get(int index) {
        rangeCheck(index);

        return elementData(index);
    }

六、ArrayListのパフォーマンス関連

  • 容量の大きさはできるだけArrayListの容量の推定値を決定することができる場合には、自動膨張によるパフォーマンスオーバーヘッドを回避する、コンストラクタ公共のArrayList(INT InitialCapacityの値)指定されたサイズを呼び出します。
  • 使用trimToSize()内部のArrayList配列のサイズはスペースを節約するために、実際のサイズに縮小されます
    public void trimToSize() {
        modCount++;
        if (size < elementData.length) {
            elementData = (size == 0)
              ? EMPTY_ELEMENTDATA
              : Arrays.copyOf(elementData, size);
        }
    }

おすすめ

転載: www.cnblogs.com/tangquanbin/p/10958315.html