Java ArrayList
。]に関する基本的な質問があります。
ArrayList
がデフォルトコンストラクターを使用して宣言および初期化されると、10個の要素のメモリスペースが作成されます。さて、11番目の要素を追加すると、どうなりますか? 20(またはそれ以上)の要素容量で新しいメモリ空間が作成されます(これには、最初のメモリ位置から新しい位置に要素をコピーする必要があります)OR他のもの?
here をチェックしました。しかし、答えが見つかりませんでした。
知識を共有してください。ありがとう。
新しい配列が作成され、古い配列の内容がコピーされます。 APIレベルで知っているのはそれだけです。 ドキュメント (私の強調)から引用:
各
ArrayList
インスタンスには容量があります。容量は、リスト内の要素を格納するために使用される配列のサイズです。常に少なくともリストのサイズと同じ大きさです。 ArrayListに要素が追加されると、その容量は自動的に増加します。 成長ポリシーの詳細は、要素を追加すると一定の償却時間コストがかかるという事実以外には指定されません。
ArrayList
の特定の実装(Sunのような)で実際にどのように発生するかという観点からは、ソースの詳細な詳細を見ることができます。しかし、もちろん、特定の実装の詳細に依存することは通常、良いアイデアではありません...
SunのJDK6:
私はそれが15要素に成長すると信じています。コーディングはしていませんが、jdkのgrow()コードを見てください。
int newCapacity then = 10 +(10 >> 1)= 15.
_/**
* Increases the capacity to ensure that it can hold at least the
* number of elements specified by the minimum capacity argument.
*
* @param minCapacity the desired minimum capacity
*/
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
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);
}
_
Javadocから、これはJava 2以降からであると言われているため、Sun JDKでの安全な賭けです。
[〜#〜] edit [〜#〜]:乗算係数_1.5
_とint newCapacity = oldCapacity + (oldCapacity >> 1);
の関係を理解できなかった人向け
_>>
_は、数値を半分に減らす右シフト演算子です。副<文>この[前述の事実の]結果として、それ故に、従って、だから◆【同】consequently; therefore <文>このような方法で、このようにして、こんなふうに、上に述べたように◆【同】in this manner <文>そのような程度まで<文> AひいてはB◆【用法】A and thus B <文>例えば◆【同】for example; as an example、int newCapacity = oldCapacity + (oldCapacity >> 1);
=> _int newCapacity = oldCapacity + 0.5*oldCapacity;
_
=> _int newCapacity = 1.5*oldCapacity ;
_
それは実装に依存しますが、Sun Java 6ソースコードから:
int newCapacity = (oldCapacity * 3)/2 + 1;
それはensureCapacity
メソッドにあります。他のJDK実装は異なる場合があります。
配列リストにオブジェクトを追加しようとすると、
Javaチェック既存の配列に新しいオブジェクトを保持するのに十分な容量があることを確認します。そうでない場合、-より大きなサイズの新しい配列が作成されます、古い配列が新しい配列にコピーされますArrays.copyOfと新しい配列を使用して既存のアレイに割り当てられます。
以下のコードを見てください(Java GrepCode.comのArrayList Code)から取得)。
編集:
public ArrayList()初期容量が10の空のリストを作成します。
public ArrayList(int initialCapacity)初期容量を指定できます。
public ArrayList(Collection c)指定されたコレクションの要素を含むリストを、コレクションの反復子によって返される順序で構築します。
ArrayList()コンストラクタを使用すると、Size = 1でArrayListを取得します。リストに11番目の要素を追加すると、ensureCapacity()メソッド内に新しいArraylistが作成されます。
次の式を使用します。
int newCapacity= (oldCapacity * 3)/2 +1;
arrayListが宣言され、デフォルトコンストラクターを使用して初期化されると、10個の要素のメモリスペースが作成されます。今、11番目の要素を追加すると、何が起こるか
ArrayListは、次のサイズの新しいオブジェクトを作成します
つまり、OldCapacity * 3/2 + 1 = 10 * 3/2 + 1 = 16
通常、ArrayListタイプのコンテナのメモリは、2倍にすることで増加します。したがって、最初に10個のアイテム用のスペースがあり、10個を追加した場合、11個目のアイテムは20個のアイテムの新しい(内部)配列に追加されます。この理由は、配列が固定サイズの増分でNice O(n)内部配列がいっぱいになるたびにサイズを調整します。
JDK 6までは、式newCapacity = (oldCapacity * 3/2) + 1
で容量が増加します。
JDK 7以降では、式はnewCapacity = oldCapacity + (oldCapacity >> 1)
に変わります。
したがって、初期容量が10
その後、新しい容量は16 in JDK6
および15 in above JDK6
コンテキストJava 8
ここでOracle Java 8実装のコンテキストで答えを出します。すべての答えを読んだ後、Java 6のコンテキストで答えが見つかりました。はgmgmillerによって与えられ、別の答えがJava 7のコンテキストで与えられました。しかし、Java 8はサイズの増加を実装する方法は与えられていません。
Java 8では、サイズ増加の動作はJava 6と同じです。ArrayListのgrow
メソッドを参照してください。
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
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);
}
キーコードは次の行です。
int newCapacity = oldCapacity + (oldCapacity >> 1);
したがって、成長因子も1.5であり、Java 6。
ArrayListが既定のコンストラクターを使用して宣言および初期化されると、10個の要素のメモリスペースが作成されます。
番号。 ArrayListが初期化されると、空の配列に対してメモリ割り当てが行われます。デフォルトの容量(10)のメモリ割り当ては、ArrayListへの最初の要素の追加時にのみ行われます。
/**
* The array buffer into which the elements of the ArrayList are stored.
* The capacity of the ArrayList is the length of this array buffer. Any
* empty ArrayList with elementData == EMPTY_ELEMENTDATA will be expanded to
* DEFAULT_CAPACITY when the first element is added.
*/
private transient Object[] elementData;
追伸質問にコメントするほどの評判がありません。だから誰もこの間違った仮定を先に指摘しなかったので、これを答えとしています。
ArrayList
のサイズは、常にn+n/2+1
で増加します。
ArrayListは、次の場合に負荷係数のサイズを増やします。
コンテキスト:JDK 7
ArrayList
に要素を追加する際、次のpublic ensureCapacityInternal
呼び出しと他のプライベートメソッド呼び出しは、サイズを増やすために内部的に行われます。これは、ArrayList
のサイズを動的に増加させるものです。コードを表示しながら、命名規則によってロジックを理解できます。そのため、明示的な説明を追加していません。
public boolean add(E paramE) {
ensureCapacityInternal(this.size + 1);
this.elementData[(this.size++)] = paramE;
return true;
}
private void ensureCapacityInternal(int paramInt) {
if (this.elementData == EMPTY_ELEMENTDATA)
paramInt = Math.max(10, paramInt);
ensureExplicitCapacity(paramInt);
}
private void ensureExplicitCapacity(int paramInt) {
this.modCount += 1;
if (paramInt - this.elementData.length <= 0)
return;
grow(paramInt);
}
private void grow(int paramInt) {
int i = this.elementData.length;
int j = i + (i >> 1);
if (j - paramInt < 0)
j = paramInt;
if (j - 2147483639 > 0)
j = hugeCapacity(paramInt);
this.elementData = Arrays.copyOf(this.elementData, j);
}
Jdk 1.6の場合:新しい容量=(現在の容量* 3/2)+ 1;
Jdk 1.7の場合:
int j = i +(i >> 1);これは、新しい容量=(現在の容量* 1/2)+現在の容量と同じです。
例:サイズは:10-> 15-> 22-> 33のように増加します
ArrayListのデフォルトの容量は10です。Capacityが最大容量に達すると、ArrayListのサイズは16になります。容量が最大容量の16に達すると、ArrayListのサイズは25になり、データサイズに基づいて増加し続けます。 ...
どうやって?ここに答えと式があります
New capacity = (Current Capacity * 3/2) + 1
したがって、デフォルトの容量が10の場合、
Current Capacity = 10
New capacity = (10 * 3/2) + 1
Output is 16
static int getCapacity(ArrayList<?> list) throws Exception {
Field dataField = ArrayList.class.getDeclaredField("elementData");
dataField.setAccessible(true);
return ((Object[]) dataField.get(list)).length;
}
上記のメソッドを使用して、arraylistが変更されているときにサイズを確認します。