CodeGym /Java Blog /ランダム /写真のArrayList
John Squirrels
レベル 41
San Francisco

写真のArrayList

ランダム グループに公開済み
やあ!今日のレッスンはArrayList前のレッスンよりも簡単でもあり、難しいものでもあります。
写真の ArrayList - 1
今日は内部を調べて、ArrayListさまざまな操作中に何が起こるかを研究するので、それはさらに困難になるでしょう。一方、このレッスンにはコードはほとんどありません。ほとんど写真と説明です。さあ、行きましょう:) すでにご存知のとおり、ArrayList内部にはデータ ストアとして機能する通常の配列があります。ほとんどの場合、リストの正確なサイズは指定されません。ただし、内部配列にはある程度のサイズが必要です。そしてその通りです。デフォルトのサイズは 10 です

public static void main(String[] args) {
   ArrayList<Car> cars = new ArrayList<>();
}
写真の ArrayList - 2 まず、新しい要素の追加がどのようなものかを見てみましょう。最初の作業は、内部配列に十分なスペースがあるかどうか、およびもう 1 つの要素が収まるかどうかを確認することです。スペースがある場合は、新しい要素がリストの最後に追加されます。「最後まで」というときは、配列内の最後の位置を意味するわけではありません (それは奇妙です)。最後の現在の要素に続く位置を意味します。そのインデックスは になりますcars.size()。現在リストは空です ( cars.size() == 0)。したがって、新しい要素は位置 0 に追加されます。

ArrayList<Car> cars = new ArrayList<>();
Car ferrari = new Car("Ferrari 360 Spider");
cars.add(ferrari);
写真の ArrayList - 3 それは十分明らかです。真ん中、つまり他の要素の間に挿入するとどうなるでしょうか?

public static void main(String[] args) {
   ArrayList<Car> cars = new ArrayList<>();
   Car ferrari = new Car("Ferrari 360 Spider");
   Car bugatti = new Car("Bugatti Veyron");
   Car lambo = new Car("Lamborghini Diablo");
   Car ford = new Car("Ford Modneo");
  
   cars.add(ferrari);
   cars.add(bugatti);
   cars.add(lambo);
  
   cars.add(1, ford);// add ford to cell 1, which is already occupied
}
繰り返しますが、最初に配列内に十分なスペースがあるかどうかがチェックされます。十分なスペースがある場合、要素は新しい要素を挿入する位置から右にシフトされます。位置 1 に挿入します。つまり、位置 3 の要素が位置 4 にコピーされ、要素 2 が位置 3 に、要素 1 が位置 2 にコピーされます。その後、新しい要素がその場所に挿入されます 写真の ArrayList - 4 。前の要素 (bugatti) はすでにそこから新しい位置にコピーされています。 写真の ArrayList - 5 ここで、配列に新しい要素を挿入する場所がない場合に、このプロセスがどのように行われるかを見てみましょう。 写真の ArrayList - 6 当然のことながら、最初に十分なスペースがあるかどうかがチェックされます。十分なスペースがない場合は、新しい配列が内部に作成されます。ArrayListそのサイズは、古い配列のサイズに 1.5 を加えたものに 1 を加えたものです。この場合、新しい配列のサイズは 16 になります。現在の要素はすべてそこにすぐにコピーされます。 写真の ArrayList - 7 古い配列はガベージ コレクターによって削除され、新しい拡張された配列のみが残ります。ここに新しい要素を入れる余地があります。占有されている位置 3 に挿入します。さて、おなじみの手順が始まります。インデックス 3 から始まるすべての要素が 1 つ右にシフトされ、新しい要素が静かに追加されます。 写真の ArrayList - 8 そして挿入完了!そして挿入が完了しました。次に、アイテムの削除について話しましょう。配列を扱うときに問題が発生したことを覚えているでしょう。要素を削除すると配列に「穴」ができます。削除するたびに、この変更を実行するたびに独自のコードを作成する必要がありました。 ArrayList も同じ原則に従いますが、このメカニズムはすでに実装されています。 写真の ArrayList - 9 これはどのように見えるかです: 写真の ArrayList - 10 そして最終的には、必要なものが得られます: 写真の ArrayList - 11 要素lamboが削除されました。ここでは、真ん中の要素を削除しました。明らかに、リストの末尾から要素を削除する方が高速です。他の要素をすべて移動する必要がなく、その要素が単に削除されるだけだからです。内部配列の次元とそれがメモリ内でどのように配置されるかについて、もう一度お話しましょう。 配列の拡張にはある程度のリソースが必要です。 したがって、ArrayList少なくとも 100 個の要素が含まれることが確実な場合は、デフォルトのサイズを使用します。100 番目の要素を挿入するまでに 内部配列を6 回展開する必要があり、そのたびにすべての要素をシフトする必要があります。
  • 10要素から16要素へ
  • 16要素から25要素へ
  • 25から38まで
  • 38から58まで
  • 58から88まで
  • 88 から 133 (つまり、古い配列のサイズに 1.5 を加えたもの)
ご想像のとおり、これは非常にリソースを大量に消費します。 したがって、必要な項目数が (おおよそでも) わかっている場合は、特定のサイズの配列を含むリストを作成することをお勧めします。

ArrayList<Car> cars = new ArrayList<>(100);
100 要素の配列のメモリが一度に割り当てられるようになり、配列の効率が向上します (拡張する必要がなくなります)。この戦略には裏もあります。 からオブジェクトを削除してもArrayList、内部配列のサイズは自動的には減少しません。ArrayList88 個の要素からなる完全な内部配列を 持つ があるとします。写真の ArrayList - 12 プログラムが実行されると、77 個の要素が削除されるため、11 個だけが残ります。 写真の ArrayList - 13 問題が何であるかはすでにわかりましたか? わかりました、メモリの使用が非効率的です。ここでは 11 個の位置だけを使用していますが、88 個の要素にメモリを割り当てています。これは必要量の 8 倍です。ArrayListこの場合、クラスの特別なメソッドの1 つを使用してメモリ使用を最適化できます。trimToSize()。このメソッドは、内部配列の長さを、現在そこに格納されている要素の数まで「トリミング」します。 写真の ArrayList - 14 これで、必要なだけのメモリが割り当てられました。:)
コメント
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION