私は、中に何か面白い渡ってつまずくように見える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");
そして、一見何の内側elementData
(Object[]
すべての要素が保存されている場合)には報告します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は、明示的に指定する最初のものです)