この記事では、ArrayListのソースコードを分析します。それらを分析する前に、アレイについて話させてください。配列は、私たちが接触した最初のデータ構造の1つである可能性があります。それらは、要素を保存するためにメモリ内の連続アドレス空間を分割します。メモリを直接動作するため、配列のパフォーマンスはコレクションクラスのパフォーマンスよりも優れています。これは、配列を使用することの大きな利点です。しかし、配列には致命的な欠陥があることを知っています。つまり、アレイのサイズを初期化中に指定する必要があり、後続の操作では配列のサイズを変更できません。実際の状況では、最初に保存される要素の数がわからないことがわかりますが、代わりに、コンテナがより多くの要素を保存できるように自動的に容量を拡張できることを期待しています。 ArrayListはそのようなニーズを非常にうまく満たすことができ、サイズを自動的に拡張して、ストレージ要素の継続的な増加に適応することができます。その基礎となる層は配列に基づいて実装されているため、変更が速く、挿入と削除が遅いなど、アレイのいくつかの機能があります。この記事では、ソースコードを深く掘り下げて、アレイをカプセル化する方法を確認します。まず、メンバー変数と3つの主要なコンストラクターを見てください。
? if(initialcapacity <0){新しいIllegalargumentException( "違法容量:"+ initial -capacity); } //指定された容量の新しいオブジェクトタイプ配列を作成しますthis.elementData = new object [initialCapacity];} //パラメーターなしのコンストラクターpublic arrayList(){super(); //空の配列インスタンスをelementData this.ElementData = empty_ElementData;} //外部コレクションパブリックアレイリスト(collection <?extends e> c)に渡すためのコンストラクターメソッド{//コレクションelementData = C.ToArray(); //コレクションサイズの要素の数を更新= elementData.length; //配列のタイプの参照を判断し、参照をオブジェクト配列参照に変換するif(elementData.getClass()!= object []。class){elementData = arrays.copyof(elementData、size、object []。class); }}ArrayListの内部ストレージ構造はオブジェクトタイプの配列であるため、あらゆるタイプの要素を保存できることがわかります。 ArrayListを構築すると、初期サイズが渡されると、指定された容量の新しいオブジェクト配列が作成されます。初期サイズが設定されていない場合、メモリスペースを割り当てるのではなく、空のオブジェクト配列を使用し、要素を実際に配置するときにメモリを割り当てます。追加、削除、変更、検索の方法を見てみましょう。
// Public Boolean Add(e e){//追加する前に配列を拡張する必要があるかどうかを確認してください。最小配列の長さはサイズ + 1 suresecapacityinternal(size + 1)です。 //配列elementDataの端に要素を追加[size ++] = e; true;} //増加(挿入)public void add(int index、e element){//位置範囲チェックrangecheckforadd(index); //容量を拡張する必要があるかどうかを確認します。 //挿入位置System.ArrayCopy(elementData、index、elementData、index + 1、size -index)の後ろに要素を移動します。 //新しい値elementData [index] = elementを割り当てます。 size ++;} // public e remove(int index){// indexはサイズより大きくすることはできませんrangecheck(index); modcount ++; e oldvalue = elementData(index); int nummoved = size -index -1; if(nummoved> 0){// 1つのsystem.ArrayCopy(elementData、index+1、elementData、index、nummoved)によってインデックスの前方に要素を移動します。 } //空の参照elementData [ - size] = null; return oldvalue;} // public e set(int index、e element){// indexはsize rangecheck(index)より大きくすることはできません。 e oldvalue = elementData(index); //新しい要素elementData [index] = element; return oldvalue;} // public e get(int index){// indexはsize rangecheck(index)より大きくすることはできません。 //指定された位置要素を返す要素elementData(index);}要素がコレクションに追加されるたびに、まず容量が十分かどうかを確認します。そうしないと、容量が拡張されます。容量拡張の詳細については、以下で説明します。まず、特定のポイントを見て、追加、削除、変更、およびチェックするときに注意を払ってみましょう。
追加(追加):この要素を最後に追加するだけです。クイック操作。
追加(挿入):挿入位置の背後にある要素を移動する必要があり、配列のコピーが含まれるため、動作が遅くなります。
削除:削除位置の背後にある要素を前方に移動する必要があるため、配列コピーも設計されるため、操作が遅くなります。
変更:要素の動きや配列のコピーを伴わずに、指定された場所の要素を直接変更すると、操作は高速です。
チェック:指定された添え字の配列要素を直接返し、操作は高速です。
ソースコードから、検索と変更はアレイサブスクリプトに直接配置されるため、要素の動きと配列のコピーが含まれないため、より速くなります。ただし、要素を移動する必要があるため、配列のコピーが含まれるため、操作が遅くなります。さらに、各追加操作はアレイ拡張を実行する場合があり、パフォーマンスにも影響します。 ArrayListがその容量を動的に拡大する方法を見てみましょう。
private void ensurecapacityinternal(int mincapacity){//この時点でアレイがまだ空である場合(elementData == empty_ElementData){//デフォルトの容量と比較すると、より大きな値mincapacity = math.max(default_capacity、mincapacity); } //配列が初期化されている場合、このステップを実行してくださいseresexplicitcapacity(mincapacity);} private void suresexplicitcapacity(int mincapacity){modcount ++; //最小容量が配列の長さよりも大きい場合、if(mincapacity -elementdata.length> 0){grow(mincapacity); }} //コレクションの最大容量private private static final int max_array_size = integer.max_value -8; //配列長プライベートボイド成長(int mincapacity){//配列の元の容量を取得int oldcapacity = elementdata.length; //新しい配列の容量、元のベースで半分を追加しますint newcapacity = oldcapacity +(oldcapacity >> 1); //新しい容量が最小容量よりも少ないかどうかを確認します(newcapacity -mincapacity <0){newcapacity = mincapacity; } //新しい容量が最大配列容量を超えるかどうかを確認します(newcapacity -max_array_size> 0){newcapacity = hugecapacity(mincapacity); } //元の配列を新しい配列にコピーしますelementData = arrays.copyof(elementData、newCapacity);}要素を追加する前に、EnsureCapacity -Internalは収集能力チェックのために呼び出されます。このメソッド内では、現在のコレクションの内部配列がまだ空の配列であるかどうかを確認します。もしそうなら、デフォルトのサイズが10の新しいオブジェクト配列を作成します。そうでない場合は、現在のコレクションが初期化されていることを証明します。次に、suresexplicitcapacityメソッドを呼び出して、現在の配列の容量が最小必要な容量を満たしているかどうかを確認します。満足していない場合は、拡張するためにGrow Methodを呼び出します。 Grow Methodでは、各拡張が元の配列の長さの半分を増やすことであることがわかります。拡張は、実際には、より大きな容量の新しい配列を作成し、元の配列のすべての要素を新しい配列にコピーしてから、元の配列を破棄して新しい配列を使用することです。これまでのところ、ArrayListでより一般的に使用されるメソッドと、注目に値する重要なポイントの一部を分析しました。
1. ArrayListの基礎となる実装は配列に基づいているため、指定されたサブスクリプトの検索と変更は高速ですが、削除と挿入操作は遅くなります。
2。アレイリストを構築するときは、拡張によって引き起こされるアレイコピー操作を削減するために、可能な限り容量を指定してみてください。サイズがわからない場合は、デフォルト容量を10に割り当てることができます。
3。要素を追加する前に、容量拡張が必要かどうかを確認します。各容量の拡張は、元の容量の半分です。
4.添え字操作が操作されるたびに、セキュリティチェックが実行されます。配列が範囲外である場合、例外はすぐにスローされます。
5.すべてのArrayListメソッドは同期されていないため、スレッドは安全ではありません。
6.上記の分析はJDK1.7に基づいており、他のバージョンにはいくつかの違いがあるため、一般化することはできません。
上記はこの記事のすべての内容です。みんなの学習に役立つことを願っています。誰もがwulin.comをもっとサポートすることを願っています。