なぜ内部配列の異なる成長率原因別のArrayListのコンストラクタを使用していますか?

ユージン:

私は、中に何か面白い渡ってつまずくように見えるArrayList私の周り私の頭をラップすることができないことを実現。ここでのショーは、私が何を意味するかといういくつかのコードは次のとおりです。

public class Sandbox {

    private static final VarHandle VAR_HANDLE_ARRAY_LIST;

    static {
        try {
            Lookup lookupArrayList = MethodHandles.privateLookupIn(ArrayList.class, MethodHandles.lookup());
            VAR_HANDLE_ARRAY_LIST = lookupArrayList.findVarHandle(ArrayList.class, "elementData", Object[].class);
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException();
        }
    }

    public static void main(String[] args) {

        List<String> defaultConstructorList = new ArrayList<>();
        defaultConstructorList.add("one");

        Object[] elementData = (Object[]) VAR_HANDLE_ARRAY_LIST.get(defaultConstructorList);
        System.out.println(elementData.length);

        List<String> zeroConstructorList = new ArrayList<>(0);
        zeroConstructorList.add("one");

        elementData = (Object[]) VAR_HANDLE_ARRAY_LIST.get(zeroConstructorList);
        System.out.println(elementData.length);

    }
}

あなたが作成した場合のアイデアがあるArrayList。このように:

List<String> defaultConstructorList = new ArrayList<>();
defaultConstructorList.add("one");

そして、一見何の内側elementDataObject[]すべての要素が保存されている場合)には報告します10したがって、あなたは一つの要素を追加する-あなたは未使用されている9追加のスロットを取得します。

場合は、他の一方で、あなたが実行します。

List<String> zeroConstructorList = new ArrayList<>(0);
zeroConstructorList.add("one");

あなたは一つの要素を追加し、予約済みスペースは、ちょうどその要素のためである何よりも、。

内部的にはこの2つのフィールドを介して達成されています。

/**
 * Shared empty array instance used for empty instances.
 */
private static final Object[] EMPTY_ELEMENTDATA = {};

/**
 * Shared empty array instance used for default sized empty instances. We
 * distinguish this from EMPTY_ELEMENTDATA to know how much to inflate when
 * first element is added.
 */
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

あなたが作成する場合ArrayListを経由してnew ArrayList(0)- EMPTY_ELEMENTDATA使用されます。

あなたは、作成した場合ArrayListを経由してnew Arraylist()- DEFAULTCAPACITY_EMPTY_ELEMENTDATA使用されています。

私の中から直感的な部分が-単に「削除悲鳴DEFAULTCAPACITY_EMPTY_ELEMENTDATA」として扱われるすべてのケースをみましょうEMPTY_ELEMENTDATAもちろん、コードのコメントの:

私たちは、最初の要素が追加されたときに膨張するためにどのくらい知っているEMPTY_ELEMENTDATAからこれを区別する

メイクセンスを行いますが、なぜ1がに膨らませるだろう10(私は尋ねたよりも多くのロット)とする他の1 1(正確に同じくらい私が要求されるように)。


あなたが使用している場合でもList<String> zeroConstructorList = new ArrayList<>(0)、および要素を追加し続ける、最終的にはあなたがポイントになりますelementData要求されたものよりも大きいです。

    List<String> zeroConstructorList = new ArrayList<>(0);
    zeroConstructorList.add("one");
    zeroConstructorList.add("two");
    zeroConstructorList.add("three");
    zeroConstructorList.add("four");
    zeroConstructorList.add("five"); // elementData will report 6, though there are 5 elements only

しかし、それが成長する速度は、デフォルトコンストラクタの場合よりも小さくなっています。


これは、について私に思い出させるHashMapバケットの数はほとんど常にあなたが尋ねたよりも多くあるの実装、。しかし、理由はいえ、ここで、ない場合に必要なバケット「2のべき乗」の必要性が行われています。

そこで、質問です - 缶誰かが私には、この違いを説明しますか?

ホルガー:

あなたは、あなたも実装が異なっていた古いバージョンで、指定されたものを、それぞれ、を求めたものを正確に取得します:

ArrayList()

10の初期容量で空のリストを作成します。

ArrayList(int)

指定された初期容量で空のリストを作成します。

だから、構築ArrayListデフォルトコンストラクタとすると得られますArrayListように長いリストのサイズが10以下であると、何のサイズ変更操作は、これまで必要とされず、10の初期容量を持ちます。

これとは対照的に、とのコンストラクタintの引数は正確に、対象指定された容量を使用します成長政策として指定されています

成長政策の詳細は、要素を追加すると、一定の償却時間コストを持っているという事実を超えて指定されていません。

これはあなたがゼロの初期容量を指定した場合にも適用されます。

ジャワ図8は、第1の要素が追加されるまで、10素子アレイの作成が延期されること最適化を追加しました。これは、具体的という一般的なケース取り組んでいるArrayList(デフォルトの容量を使用して作成)のインスタンスが長時間、あるいは彼らの全体の寿命のために空のままに。最初の実際の操作である場合、さらに、addAllそれは、最初の配列サイズ変更操作をスキップするかもしれません。これらは通常、慎重に選択されているように、これは、明示的な初期容量を持つリストには影響しません。

で述べたように、この答えは

この最適化は、圧倒的大多数の場合に有効となりますので、私たちのパフォーマンス分析チームによると、ArrayListのインスタンスの約85%がデフォルトのサイズで作成されます。

動機は、戻るときに定義された指定されたデフォルトの容量、触れないように、正確にこれらのシナリオを最適化することであったArrayList作成されましたが。(ただしJDK 1.4は、明示的に指定する最初のものです)

おすすめ

転載: http://43.154.161.224:23101/article/api/json?id=120723&siteId=1