.NET データ構造:
ArrayList と List が実際に異なる理由についての会話の続き
配列
あるユーザーが述べているように、配列は「古い学校」のコレクションです (はい、配列は の一部ではありませんが、コレクションと見なされますSystem.Collections
)。しかし、他のコレクション、つまりタイトルにリストしたもの (ここでは ArrayList と List(Of T)) と比較して、配列についての「古い学校」とは何ですか? 配列を見て基本から始めましょう。
まず、Microsoft .NET の配列は、「複数の [論理的に関連する] アイテムを 1 つのコレクションとして扱うことを可能にするメカニズム」です (リンクされた記事を参照)。どういう意味ですか?配列は、個々のメンバー (要素) を順番に格納し、開始アドレスを使用してメモリ内に 1 つずつ順番に格納します。配列を使用することで、そのアドレスから順番に格納された要素に簡単にアクセスできます。
それを超えて、101 の一般的な概念をプログラミングすることに反して、配列は実際には非常に複雑になる可能性があります。
配列は、1 次元、多次元、またはジャッド配列にすることができます (ジャグ配列については、読む価値があります)。配列自体は動的ではありません。初期化されると、 nサイズの配列は、 n個のオブジェクトを保持するのに十分なスペースを予約します。配列内の要素の数は増減できません。Dim _array As Int32() = New Int32(100)
配列が 100 個の Int32 プリミティブ型オブジェクトを格納できるようにメモリ ブロックに十分なスペースを予約します (この場合、配列は 0 を格納するように初期化されます)。このブロックのアドレスが に返され_array
ます。
この記事によると、共通言語仕様(CLS) では、すべての配列が 0 から始まる必要があります。.NET の配列は、非ゼロ ベースの配列をサポートします。ただし、これはあまり一般的ではありません。ゼロから始まる配列の「共通性」の結果として、Microsoft はパフォーマンスの最適化に多くの時間を費やしてきました。したがって、1 次元のゼロベース (SZ) 配列は「特別」であり、(多次元などとは対照的に) 配列の実際の実装としては最適です。SZ には、それらを操作するための特定の中間言語命令があるためです。
配列は常に参照によって (メモリ アドレスとして) 渡されます。これは、知っておくべき配列パズルの重要なピースです。それらは境界チェックを行いますが (エラーをスローします)、配列で境界チェックを無効にすることもできます。
繰り返しになりますが、配列の最大の障害は、サイズを変更できないことです。それらには「固定」容量があります。ArrayList と List(Of T) を歴史に紹介します。
ArrayList - 非ジェネリック リスト
ArrayList (いくつかのList(Of T)
重要な違いがありますが、ここでは後で説明します) は、(広い意味で) コレクションへの次の追加としておそらく最もよく考えられています。ArrayList は、IList ('ICollection' の子孫) インターフェイスから継承します。ArrayLists 自体は、Listsよりもかさばり、より多くのオーバーヘッドが必要です。
IList
ArrayLists を固定サイズのリスト (Arrays など) として処理する実装を有効にします。ただし、ArrayLists によって追加された追加の機能を超えて、固定サイズの ArrayLists を使用しても実際の利点はありません。この場合、ArrayLists (Arrays よりも) は著しく遅くなります。
私の読書から、ArrayListsはギザギザにすることはできません:「多次元配列を要素として使用する...サポートされていません」。繰り返しますが、ArrayLists の棺桶に別の釘が刺さっています。ArrayList も「型指定」されていません。つまり、すべての下にある ArrayList は、単純にオブジェクトの動的配列ですObject[]
。これには、ArrayLists を実装するときに多くのボックス化 (暗黙的) およびボックス化解除 (明示的) が必要であり、これもオーバーヘッドに追加されます。
根拠のない考え: ArrayLists は、Arrays から List-type Collections に移行しようとする試みの概念的な子のようなものであると読んだり、教授の 1 人から聞いたりしたことを覚えていると思います。コレクションに関してさらなる開発が行われたため、それらはもはや最良の選択肢ではありません
List(Of T): ArrayList がどうなったか (そしてそうなることを望んでいた)
メモリ使用量の違いは、List(Of Int32) が同じプリミティブ型を含む ArrayList よりも 56% 少ないメモリを消費するほど十分に重要です (上記の紳士のリンクされたデモンストレーションでは 8 MB 対 19 MB : 再びここにリンクされています) - ただしこれは、64 ビット マシンによって複合化された結果です。この違いは 2 つのことを示しています。まず (1)、ボックス化された Int32 型の「オブジェクト」(ArrayList) は、純粋な Int32 プリミティブ型 (List) よりもはるかに大きくなります。2 番目 (2)、違いは 64 ビット マシンの内部動作の結果として指数関数的です。
では、違いは何ですか? List(Of T)とは何ですか? MSDNはList(Of T)
、「... インデックスによってアクセスできる厳密に型指定されたオブジェクトのリスト」と定義しています。ここで重要なのは、「厳密に型指定された」ビットです。List(Of T) は型を「認識」し、オブジェクトをその型として格納します。したがって、 anは型ではなくInt32
として格納されます。これにより、ボックス化とボックス化解除によって引き起こされる問題が解消されます。Int32
Object
MSDN では、参照型ではなくプリミティブ型を格納する場合にのみ、この違いが生じると規定しています。また、違いは実際には大規模に発生します: 500 以上の要素です。さらに興味深いのは、MSDN のドキュメントに、「ArrayList クラスを使用する代わりに、List(Of T) クラスの型固有の実装を使用する方が有利です....」と書かれていることです。
基本的に、List(Of T) は ArrayList ですが、より優れています。これは、ArrayList の「一般的な同等物」です。ArrayList と同様に、ソートされるまでソートされることは保証されません (図を参照)。List(Of T) には、いくつかの追加機能もあります。