分析の二つの-ArrayListソースjdk1.8-Javaのコレクションフレームワーク

まず、それはArrayListに来るとき、私たちは皆知っているが、順序集合である、そこに添字、高速な読み出し速度として、書き込み速度が遅いです。しかし、聞いて、なぜ秩序、なぜ多くの人が答えることができなかったと推定何、なぜ、読み取り速度は、書き込み速度が遅い理由を添え字。それでは、私たちは、ビューのソースポイントから分析することがあります。

第二に、マップで見てみましょう:

この写真では、私たちが見ることができる、ArrayListクラスは抽象クラスAbstractList、実装4つのインタフェース、すなわち、Cloneableを、直列化、ランダム・、リストの4つのインターフェイスを継承します。Cloneableを、Serializableを我々は知っているこれら2つのインターフェイスが、我々は気にしない、関連のオブジェクトのクローニングおよびシーケンスです。

  1. 私たちは、RandomAccessインタフェースを見てください。
复制代码

オープンソースのコードを見て、これは、このインタフェースは、ArrayListのの役割は、高速なランダムアクセスする機能を有している空のインターフェース、そのマーカーインタフェースです。ランダムアクセスとは何ですか?これは、ArrayListの任意の要素へのランダムアクセスです。ArrayListのはそれのいずれかの要素にどのように高速なランダムアクセスであることを、我々は後で説明します。2.私たちは、図1の上から見た親AbstractList、見てみましょう。1、AbstractListは抽象クラスであり、また、Listインタフェースを実装して、私たちは推測することができ、AbstractListが行わ抽象化実装クラスの一覧抽出であります。スペース上の理由のために、コードが掲載されていません。3.次に、我々は、我々は最初のArrayListクラスは、それぞれ4つの定数、2つのインスタンス変数を定義具現ArrayListクラスコードを見る //默认容量 private static final int DEFAULT_CAPACITY = 10; //空元素数组 private static final Object[] EMPTY_ELEMENTDATA = {}; //默认容量对应的空元素数组 private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}; //元素,被transient关键字修饰,无需序列化 transient Object[] elementData; // non-private to simplify nested class access //长度 private int size; //最大长度 private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; 我々上記ArrayListオブジェクトのオブジェクトを維持するの内部を通って、ソースを推測することができるから達成するための配列、およびArrayListのデフォルトの容量は10です。4.次に、コンストラクタのArrayListを見て、ArrayListには3つのコンストラクタを定義しているが、次のとおりです。

    public ArrayList(int initialCapacity) {
        if (initialCapacity > 0) {
            //指定初始化容量,如果指定容量大于0,则设置元素数组为指定长度的对象数组;
            this.elementData = new Object[initialCapacity];
        } else if (initialCapacity == 0) {
            //如果指定容量等于0,那么设置元素数组为空数组;
            this.elementData = EMPTY_ELEMENTDATA;
        } else {
            //如果指定容易小于0,则抛出异常;
            throw new IllegalArgumentException("Illegal Capacity: "+initialCapacity);
        }
    }

    //无参构造函数,则设置元素数组为空数组
    public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }

    public ArrayList(Collection<? extends E> c) {
        //将集合转为数组,并设置为当前对象的元素数组;
        elementData = c.toArray();
        if ((size = elementData.length) != 0) {
            // 如果元素数组长度不为0,且数组对象不是Object,则将数组元素转为Object对象;
            if (elementData.getClass() != Object[].class)
                elementData = Arrays.copyOf(elementData, size, Object[].class);
        } else {
            // 如果元素数组长度为空,则替换成常量空数组;
            this.elementData = EMPTY_ELEMENTDATA;
        }
    }
复制代码
  1. 私たちは、ArrayListの中にいくつかの一般的に使用される方法の分析を詳細に説明次に、上記のすべて、取得:
    public E get(int index) {
        rangeCheck(index);
        return elementData(index);
    }
    E elementData(int index) {
        return (E) elementData[index];
    }
复制代码

もちろん、私たちは、この方法は、純粋配列のインデックス値でのArrayListを維持配列の内部動作要素である非常に簡単です取得、それを見ることができます。ArrayListのが速く読み、なぜこの時点で、最初の質問を検討?アレイは直接読み出し動作を添字ので、複雑さはO(1)です。

  1. 引数のaddメソッドを見ないように続けます。
    public boolean add(E e) { 
        //将数组长度+1作为add操作需要的最小容量传入方法中
        ensureCapacityInternal(size + 1); 
        elementData[size++] = e;    //将元素添加到数组末端,因此主要逻辑在前一句代码
        return true;
    }
    private void ensureCapacityInternal(int minCapacity) {
        ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
    }
    //根据当前元素数组长度,和add操作需要的最小容量做比较,确定操作需要的最小容量
    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;
        // 新容量=旧容量+旧容量/2;
        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);
    }
    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!!
        //该方法的作用就是将指定位置之后的元素,全部往数组末端移动一位
        System.arraycopy(elementData, index, elementData, index + 1,size - index);
        elementData[index] = element;
        size++;
    }
复制代码

、パラメータなしで、二つのステップを経るための大きな必要性をのArrayList addメソッドを参照することができ、最初のステップは、第二段階の拡大が新しい配列に、配列内の全量を、元の要素をコピーする必要がある場合、容量を計算することです。書き込みが遅いのArrayListなぜこの時点で、我々は、最初の質問に答えることができますか?ArrayListのは、構成要素の一部または全部が、同じトークンを操作を移動する、方法等セット、削除を書き込む書き込みので、全体的にこのような動作は、書き込み動作の効率が低いので。

単にこのについて話を最初の章のArrayListのJavaコレクションフレームワーク、次のセクショントークLinkedListは、異なる意見や提案があり、あなたに感謝することを歓迎します。

おすすめ

転載: juejin.im/post/5e0a14b4f265da33c42825a2