
Javaコレクションフレームワークは、一般的に再利用可能なコレクションデータ構造(コレクション)を実装するクラスとインターフェースのセットです。[ 1 ]
フレームワークと呼ばれてはいるものの、実際にはライブラリのように機能します。コレクションフレームワークは、様々なコレクションを定義するインターフェースと、それらを実装するクラスの両方を提供します。
Collection構造体と配列は、どちらもオブジェクトへの参照を保持し、グループとして管理できるという点で似ています。しかし、配列とは異なり、Collection構造体はインスタンス化時に特定の容量を割り当てる必要がありません。Collection構造体は、オブジェクトが追加または削除されると、自動的にサイズが拡大縮小します。
Collectionints は、、、longなどのプリミティブデータ型を保持できませんdouble。[ 2 ]代わりに、 s は、、、、などのラッパークラスCollectionを保持できます。[ 3 ]java.lang.Integerjava.lang.Longjava.lang.Double
Collectionは汎用的で不変ですが、配列は共変Collectionです。これは、配列と比較した場合の汎用オブジェクトの利点と考えることができます。なぜなら、状況によっては、Collection配列の代わりに汎用オブジェクトを使用すると、コンパイル時例外をスローして開発者にコードを修正するように通知することで、実行時例外を防ぐことができるからです。たとえば、開発者がオブジェクトを宣言しObject[]、特定の容量を持つObject[]新しいインスタンスによって返された値にオブジェクトを割り当てたLong[]場合、コンパイル時例外はスローされません。開発者がStringこのLong[]オブジェクトにを追加しようとすると、Java プログラムは例外をスローしますArrayStoreException。一方、開発者が代わりに の新しいインスタンスをとして宣言した場合Collection<Object>、ArrayList<Long>Java コンパイラは (正しく) コンパイル時例外をスローして、コードが互換性のない誤った型で記述されていることを通知し、実行時例外の可能性を防ぎます。開発者は、をオブジェクトCollection<Object>としてインスタンス化することでコードを修正できますArrayList<Object>。コードが Java SE7 以降のバージョンを使用している場合、開発者はダイヤモンド演算子[ 2 ]を使用してをオブジェクトCollection<Object>としてインスタンス化できます。ArrayList<>
Collectionは汎用的であるため具体化されているが、配列は具体化されていない。[ 2 ]
JDK 1.2より前のバージョンの Java プラットフォームのコレクション実装には、データ構造クラスはいくつか含まれていましたが、コレクションフレームワークは含まれていませんでした。[ 4 ] Java オブジェクトをグループ化する標準的な方法は、配列、クラスVector、Hashtableクラスを使用することでしたが、残念ながらこれらは拡張が容易ではなく、標準的なメンバーインターフェイスを実装していませんでした。[ 5 ]
再利用可能なコレクションデータ構造の必要性に対応するため、いくつかの独立したフレームワークが開発されました。[ 4 ]最もよく使用されているのは、Doug LeaのCollections パッケージ[ 6 ]とObjectSpace Generic Collection Library (JGL) [ 7 ]で、その主な目的はC++ Standard Template Library (STL) [ 8 ]との一貫性でした。
コレクションフレームワークは主にジョシュア・ブロックによって設計および開発され、JDK 1.2で導入されました。これは、ダグ・リーのコレクションパッケージから多くのアイデアとクラスを再利用しており、その結果、コレクションパッケージは非推奨となりました。[ 6 ]サン・マイクロシステムズは、コンパクトなフレームワークを求めており、C++ との一貫性は目標ではなかったため、JGL のアイデアを使用しないことを選択しました。[ 9 ]
ダグ・リーは後に、新しいコレクション関連のクラスを含む並行処理パッケージを開発しました。 [ 10 ]これらの並行処理ユーティリティの更新バージョンは、JSR 166の時点でJDK 5.0に含まれていました。
Java のマップ以外のほとんどのコレクションは、java.util.Collectionインターフェースから派生しています。は、Collectionすべてのコレクションの基本部分を定義します。
インターフェースには、それぞれに追加および削除するためのメソッドadd(E e)とメソッドがあります。また、メソッドもあり、これはをの配列に変換します(戻り値の型はです)。[ 11 ]最後に、 メソッドは、指定された要素がに存在するかどうかを確認します。remove(E e)CollectiontoArray()CollectionObjectCollectionObject[]contains(E e)Collection
インターフェースCollectionは のサブインターフェースなjava.lang.Iterableので、 はfor-eachCollectionステートメントのターゲットになり得ます。(インターフェースはfor-each ステートメントで使用されるメソッドを提供します。) すべてのは を実装し、 のすべての要素をスキャンします。Iterableiterator()Collectionjava.util.IteratorCollection
Collectionは汎用的です。任意の はCollection任意の を格納できますObject。たとえば、 の任意の実装にはオブジェクトCollection<String>が含まれます。の実装からオブジェクトStringを使用する場合、キャストは不要です。[ 12 ]山括弧には、が保持する型を指定する型引数を含めることができることに注意してください。[ 13 ]StringCollection<String>< >Collection
コレクションフレームワーク
コレクションフレームワークは、コレクションインターフェースに従うリストなどのすべてのコレクション(一般的な概念)を保持します。
コレクションの種類
コレクションには、キュー、マップ、リスト、セットなど、いくつかの種類があります。
キューを使用すると、プログラマーは特定の順序でアイテムを挿入し、同じ順序でそれらのアイテムを取得できます。例としては、待機リストがあります。キューの基本インターフェースは と呼ばれますQueue。
ディクショナリ/マップは、オブジェクトの値にアクセスするためのルックアップキーを持つオブジェクトへの参照を格納します。キーの1つの例は、IDカードです。ディクショナリ/マップの基本インターフェースは と呼ばれますMap。
リストは有限の集合であり、同じ値を複数回格納することができます。
セットは順序付けされていないコレクションであり、反復処理が可能で、各要素は最大で1回しか含まれません。セットの基本インターフェースは と呼ばれますSet。[ 3 ]
リストは、コレクションフレームワークにおいてインターフェースを介して実装されますjava.util.List。このインターフェースは、リストを基本的に配列のより柔軟なバージョンとして定義します。要素には特定の順序があり、重複する要素も許可されます。要素は特定の位置に配置でき、リスト内で検索することも可能です。
を実装する具体的なクラスはいくつかありList、およびそれに対応するすべてのサブクラス、さらに も含まれます。AbstractListCopyOnWriteArrayList
クラスの直接のサブクラスには、、およびが含まれます。AbstractListAbstractSequentialListArrayListVector
AbstractListこれは、開発者が与えられたインターフェースの独自の実装を簡単に開発できるようにすることで、インターフェースと抽象クラスの利点を活用して組み合わせた、スケルトン実装の一例です。 [ 14 ]
このjava.util.ArrayListクラスは、List配列として実装されています。に固有の関数がList必要な場合はいつでも、クラスは配列内の要素を移動させて処理を実行します。
このjava.util.LinkedListクラスは、要素をノードに格納し、各ノードは 内の前のノードと次のノードへのポインタを持っていますList。 はListポインタをたどることで走査でき、要素はポインタを変更してノードを適切な場所に配置するだけで追加または削除できます。[ 15 ]
このクラスは、直接のサブクラスとして を持ちます。これは、Java プラットフォーム ライブラリにおける継承よりも合成の原則に違反している例です。コンピュータ サイエンスでは、ベクトルは一般的にスタックではないからです。[ 16 ]このシナリオでは合成の方が適切だったでしょう。[ 16 ]VectorStack
クラスは、 を として扱うことができる 5 つの操作を備えたクラスです。スタックは を使用して作成されます。 は、 に新しいオブジェクトを配置する( メソッド) および からオブジェクトを取得する( メソッド) メソッドを提供します。 は、後入れ先出し(LIFO)に従ってオブジェクトを返します。つまり、 に最後に配置されたオブジェクトが最初に返されます。は、Java が提供するスタックの標準実装です。Stackextendsjava.util.VectorVectorStackjava.util.StackStackStackpush(E e)Stackpop()StackStackjava.util.Stack
このStackクラスは、オブジェクトの後入れ先出し (LIFO) スタックを表します。 Stack クラスには、Vectorを として扱うことができる 5 つの追加操作がありますStack。通常のpush(E e)およびpop()操作に加え、peek()の最上位項目を覗き見るメソッド ( ) 、 が空StackかどうかをテストするメソッドStack( empty())、からStack項目を検索して最上位からの距離を調べるメソッド ( search(Object o)) が提供されています。 がStack最初に作成されたときは、項目は含まれていません。
これはクラスCopyOnWriteArrayListを拡張しObject、他のクラスは拡張しません。CopyOnWriteArrayListこれにより、過剰な同期処理を行わずにスレッドセーフティを実現できます。[ 17 ]
シナリオによっては、同期が必須となる場合があります。たとえば、メソッドが静的フィールドを変更し、そのメソッドが複数のスレッドから呼び出される必要がある場合、同期は必須となり、などの並行処理ユーティリティはCopyOnWriteArrayList使用すべきではありません。[ 17 ]
しかし、同期にはパフォーマンスのオーバーヘッドが発生する可能性があります。同期が必須ではないシナリオでは、マルチコアプロセッサを活用し、 CPU使用率を高める、CopyOnWriteArrayListスレッドセーフな同期の代替手段が存在します。 [ 17 ]
このjava.util.Queueインターフェースは、要素が挿入された順序で格納されるキューデータ構造を定義します。新しい要素は行の末尾に追加され、要素は先頭から削除されます。これにより、先入れ先出し(FIFO)システムが実現されます。このインターフェースはjava.util.LinkedList、、、java.util.ArrayDequeおよびによって実装されますjava.util.PriorityQueue。
クラスの直接のサブクラスに は 、、、、、、およびが含まれます。 AbstractQueueArrayBlockingQueueConcurrentLinkedQueueDelayeQueueLinkedBlockingDequeLinkedBlockingQueueLinkedTransferQueuePriorityBlockingQueue
とはどちらも を拡張しますが、 などの他の抽象クラスは拡張しません。ArrayDequeConcurrentLinkedDequeAbstractCollectionAbstractQueue
AbstractQueueこれは、骨組み実装の一例です。
このjava.util.PriorityQueueクラスは を実装していますjava.util.Queueが、変更も加えています。[ 18 ]PriorityQueueには追加のcomparator()メソッドがあります。[ 18 ]要素は挿入された順序ではなく、優先順位で順序付けられます。優先順位を決定するために使用されるメソッドは、java.lang.Comparable#compareTo(T)要素のメソッドか、コンストラクタで指定されたメソッドのいずれかです。このクラスは、ヒープを使用してアイテムをソートした状態に保つことでこれを実現します。[ 19 ]
このjava.util.concurrent.ConcurrentLinkedQueueクラスは を拡張し、インターフェースを実装します。[ 20 ]java.util.AbstractQueueConcurrentLinkedQueuejava.util.Queue
クラスConcurrentLinkedQueueはスレッドセーフなコレクションです。なぜなら、 の中に配置された任意の要素に対して、Java Collection Library は、任意のスレッドがコレクションから要素を取得できるようにすることで、要素が安全に公開されることを保証するからです。 [ 21 ]オブジェクトの状態が他のすべてのスレッドに同時に見えるようになると、そのオブジェクトは安全に公開されたと言われます。 [ 21 ]安全な公開には通常、公開スレッドと消費スレッドの同期が必要です。[ 21 ]ConcurrentLinkedQueue
インターフェースは java.util.concurrent.BlockingQueue拡張されますQueue。[ 20 ]
インターフェースには、次の直接のサブインターフェースがあります。と。は通常の のように動作しますが、 への追加と からの削除はブロッキングです。[ 22 ]が空の で呼び出された場合 、 に項目が現れるまで指定された時間または無期限に待機するように設定できます。同様に、 メソッドを使用して項目を追加すると、のオプションの容量制限の対象となり、 メソッドは に空きスペースができるまで待機してから戻ります。インターフェースは、 を削除して の先頭を取得し、必要に応じて が空でなくなるまで待機するメソッドを導入します。 [ 23 ] [ 24 ]BlockingQueueBlockingDequeTransferQueueBlockingQueueQueueBlockingQueueremove(Object o)BlockingQueueBlockingQueueadd(Object o)BlockingQueueBlockingQueueBlockingQueuetake()BlockingQueueBlockingQueue
このインターフェースは、インターフェースを拡張します。[ 25 ]は、両端キューを作成します。通常のキューでは、挿入は末尾でのみ、削除は先頭でのみ可能ですが、このインターフェースでは、挿入または削除を先頭と末尾の両方で行うことができます。このインターフェースは、前方または後方、あるいは両方を同時に使用できるキューのようなものです。さらに、前方イテレータと後方イテレータの両方を生成できます。このインターフェースは、とによって実装されます。[ 26 ]DequeQueueDequeQueueDequeDequeQueueDequejava.util.ArrayDequejava.util.LinkedList
LinkedListもちろん、もListインターフェースを実装しており、インターフェースとしても使用できます。しかし、Queueメソッドも備えています。はインターフェースLinkedListを実装しておりjava.util.Deque、より柔軟性があります。[ 27 ]
ArrayDequeはQueue配列として実装します。と同様にLinkedList、ArrayDequeもjava.util.Dequeインターフェースを実装します。[ 27 ]
インターフェースjava.util.concurrent.BlockingDequeは を拡張しますjava.util.concurrent.BlockingQueue。[ 25 ] は に似ています。挿入または削除が可能になるまで待機する時間制限付きの挿入および削除のための同じメソッドを提供します。ただし、インターフェースは の柔軟性も提供します。挿入と削除は両端で行うことができます。ブロッキング機能は機能と組み合わされています。[ 28 ]BlockingDequeBlockingQueueDequeDeque
Java のjava.util.Setインターフェースは を定義しますSet。Setには重複する要素を含めることはできません。さらに、 にはSet順序がありません。そのため、要素をインデックスで検索することはできません。は、、 およびSetによって実装されます。java.util.HashSetjava.util.LinkedHashSetjava.util.TreeSet
Setインターフェースには、とそのサブクラス、および最終的な静的内部クラス(ここで、およびは仮型パラメータ)など、いくつかの実装があります。AbstractSetConcurrentHashMap.KeySetView<K,V>KV
AbstractSetこれはインターフェースの骨組みとなる実装です。[ 14 ]Set
の直接のサブクラスには、、、、およびが含まれます。AbstractSetConcurrentSkipListSetCopyOnWriteArraySetEnumSetHashSetTreeSet
このクラスは を継承しています。このクラスにはパブリックなコンストラクタはなく、静的ファクトリ メソッドのみが含まれています。[ 29 ]EnumSetAbstractSetEnumSet
EnumSetには静的ファクトリ メソッドが含まれています。[ 30 ]このメソッドは集約メソッドです。[ 29 ]複数のパラメータを受け取り、パラメータの型を考慮して、適切な型のインスタンスを返します。[ 29 ] 2018 年現在、Java SE8 OpenJDK の実装では、クライアントからは見えないの 2 つの実装、と を使用しています。[ 29 ]が小さな列挙型に対してパフォーマンス上の利点を提供しなくなった場合、Java コレクション ライブラリに悪影響を与えることなくライブラリから削除できます。[ 29 ]EnumSet.of()EnumSetRegularEnumSetJumboEnumSetRegularEnumSet
EnumSetは、以下に説明するように、セットの一種であるビットフィールドの良い代替物です。 [ 30 ]
従来、開発者は列挙型の要素をセットに配置する必要がある場合、各定数に異なる 2 のべき乗を割り当てるint enum パターンを使用していました。 [ 30 ]このビット表現により、開発者はビットごとの OR 演算を使用して定数をセット (ビット フィールドとも呼ばれる) に結合できます。このビット フィールド表現により、開発者は効率的なセットベースの操作や、積集合や和集合などのビットごとの算術演算を行うことができます。[ 30 ]
しかし、ビットフィールド表現アプローチには多くの問題があります。ビットフィールドは、int enum定数よりも読みにくいです。[ 30 ]また、要素がビットフィールドで表現されている場合、これらの要素すべてを反復処理することは不可能です。[ 30 ]
推奨される代替アプローチは、ビットフィールドの代わりに int 列挙型を使用するを使用することです。[ 30 ]このアプローチでは、 を使用して同じ型に属する値のセットを表します。[ 30 ]はインターフェースを実装し、ビット演算の使用を必要としないため、このアプローチはより型安全です。 [ 30 ]さらに、 メソッド メソッドなど、オブジェクトのインスタンス化を可能にする静的ファクトリが多数あります。[ 30 ]EnumSetEnumSetEnumEnumSetSetEnumSet.of()
HashSetハッシュテーブルを使用します。より具体的には、java.util.LinkedHashMapハッシュと要素を格納し、重複を防ぐためにハッシュテーブルを使用します。
このjava.util.LinkedHashSetクラスは、すべての要素を挿入順序でリンクする二重リンクリストを作成することで拡張されます。これにより、リストの反復順序が予測可能になります。HashSetSet
CopyOnWriteArraySetは同期された の並行的な代替手段です。 は、同期されたの並行的な代替手段として機能するのと同様に、反復処理中に同期を実行したりオブジェクトのコピーを作成したりする必要性を排除することで、多くの状況で並行性を向上させます。[ 31 ] 一方、 と同様に、同期が必須の場合は を使用すべきではありません。SetCopyOnWriteArrayListListCopyOnWriteArrayListCopyOnWriteArraySet
このjava.util.SortedSetインターフェースはjava.util.Set、インターフェースを拡張します。通常のとは異なりSet、の要素はSortedSet、要素のcompareTo(T o)メソッド、またはのコンストラクタに提供されるメソッドによってソートされますSortedSet。の最初と最後の要素は、それぞれとメソッドSortedSetを使用して取得でき、最小値と最大値、およびの先頭または末尾で開始または終了することで部分集合を作成できます。クラスは、インターフェースを実装します。[ 32 ]first()last()SortedSetjava.util.TreeSetSortedSet
このjava.util.NavigableSetインターフェースはjava.util.SortedSetインターフェースを拡張し、いくつかの追加メソッドを備えています。floor(E e)、ceiling(E e)、lower(E e)、higher(E e)メソッドは、パラメータに近いセット内の要素を見つけます。さらに、 内の項目に対する降順イテレータがSet提供されます。 と同様にSortedSet、java.util.TreeSetは を実装しますNavigableSet。[ 33 ]
java.util.TreeSetは、によって実装された赤黒木を使用しますjava.util.TreeMap。赤黒木は重複がないことを保証します。さらに、TreeSetを実装することもできますjava.util.SortedSet。[ 34 ]
ConcurrentSkipListSetは、同期化された実装の並行的な代替として機能します。たとえば、メソッドによってラップされたを置き換えます。[ 35 ]SortedSetTreeSetsynchronizedMap
java.util.MapJavaでは、マップはインターフェースによって定義されます。
Mapマップは、キーと要素を関連付けるデータ構造です。これにより、マップは非常に柔軟になります。キーが要素のハッシュコードである場合、マップはMap基本的にSetマップになります。キーが単に増加する数値である場合は、リストになります。
実装例としては、、、、などがあります。Mapjava.util.HashMapjava.util.LinkedHashMapjava.util.TreeMap
AbstractMapこれはスケルトン実装の一例である。[ 14 ]
クラスの直接のサブクラスには、、、、、およびが含まれます。AbstractMapConcurrentSkipListMapEnumMapHashMapIdentityHashMapTreeMapWeakHashMap
EnumMap拡張。は順序インデックス配列と同等の速度を持ちます。[ 36 ]これは、内部的に配列を使用しており、実装の詳細は開発者から完全に隠蔽されているためです。[ 36 ] したがって、EnumMap は配列のパフォーマンス上の利点を持ちながら、型の安全性も得られます。 [ 36 ]AbstractMapEnumMapEnumMapMap
HashMapハッシュテーブルを使用します。キーのハッシュを使用して、さまざまなバケット内の要素を検索します。これはハッシュベースのコレクションです。[ 37 ]HashMap
LinkedHashMapは、要素間に二重リンクリストを作成することで拡張し、マップに挿入された順序で要素にアクセスできるようにします。 には、に新しいキーが追加されるたびにメソッドによって呼び出されるメソッドが含まれています。[ 38 ]は、が true を返すたびに、最古のエントリを削除します。[ 38 ]メソッドはオーバーライドできます。[ 38 ]HashMapLinkedHashMapprotectedremoveEldestEntryputMapMapremoveEldestEntryremoveEldestEntry
TreeMapとは対照的に、 は赤黒木を使用します。キーはツリー内のノードの値として使用され、ノードは 内の要素を指します。[ 39 ]HashMapLinkedHashMapMap
ConcurrentHashMapは と似ており、ハッシュベースのコレクションでもあります。[ 37 ]ただし、使用するロック戦略の違いなど、いくつかの違いがあります。HashMap
は、スケーラビリティと並行性を向上させるために、まったく異なるロック戦略を使用します。[ 37 ]は、同じロックを使用してすべてのメソッドを同期しません。[ 37 ]代わりに、ロック ストライピングと呼ばれるメカニズムを使用します。[ 37 ]このメカニズムは、よりきめ細かいロック メカニズムを提供します。[ 37 ]また、より高いレベルの共有アクセスも許可します。[ 37 ]ConcurrentHashMapConcurrentHashMapConcurrentHashMap
ConcurrentSkipListMapは、同期化された実装の並行的な代替として機能します。は、メソッドによってラップされたを置き換えるため、と非常によく似ています。[ 35 ]SortedMapConcurrentSkipListMapConcurrentSkipListSetConcurrentSkipListMapTreeMapsynchronizedMap
このjava.util.SortedMapインターフェースは、java.util.Mapインターフェースを拡張します。このインターフェースは、Map指定されたキーでソートされた を定義します。compareTo()のコンストラクタで提供されるメソッド、またはメソッドを再度使用してSortedMap、キーと要素のペアはキーでソートされます。 の最初と最後のキーは、それぞれメソッドとメソッドMapを使用して呼び出すことができます。さらに、メソッドを使用して、最小キーと最大キーからサブマップを作成できます。は によって実装されます。[ 40 ]firstKey()lastKey()K) subMap(K fromKey, K toKey)SortedMapjava.util.TreeMap
インターフェースはさまざまな方法でjava.util.NavigableMap拡張java.util.SortedMapできます。指定されたキーに最も近いキーまたはマップエントリをどちらの方向にも見つけるメソッドを呼び出すことができます。マップを反転することもでき、そこから逆順のイテレータを生成できます。これはによって実装されていますjava.util.TreeMap。[ 41 ]
このjava.util.concurrent.ConcurrentMapインターフェースは、Javaプログラミング言語のJava Collections Frameworkバージョン1.5で導入されたjava.util.Mapスレッドセーフなインターフェースです。[ 20 ]Map
JavaコレクションフレームワークはApache Commons Collectionsライブラリによって拡張されており、バッグや双方向マップなどのコレクション型、およびユニオンやインターセクションを作成するためのユーティリティが追加されています。[ 42 ]
Googleは、Guavaライブラリの一環として、独自のコレクションライブラリを公開しました。
Collections が待望のデビューを果たす前は、Java オブジェクトをグループ化する標準的な方法は、配列、Vector、および Hashtable を使用することでした。これら 3 つのコレクションはすべて、メンバーにアクセスするための異なるメソッドと構文を持っています。配列は角括弧 ([]) 記号を使用し、Vector は elementAt メソッドを使用し、Hashtable は
および
メソッドを使用します。
getput
Java Development Kit JDK1.2には、ついに標準的なコレクションクラスセットが含まれています。設計と実装に若干の違いはありますが、JDK1.2パッケージには、このパッケージとほぼ同じ基本的な抽象化、構造、機能が含まれています。そのため、このコレクションパッケージは今後更新されません。
Java 自体と同様に、Java ジェネリックライブラリは C++ 陣営から多くのものを借用しています。C++ の STL の最良の部分を取り入れ、C++ の欠点は取り除いています。今日のほとんどの C++ プログラマーは STL を知っていますが、その潜在能力を十分に活用できている人はごくわずかです。
ObjectSpace Inc. の JGL と Sun の Collections Framework を比較するのは、リンゴとキウイフルーツを比較するようなものだ。一見すると、この 2 つのフレームワークは同じ開発者を奪い合っているように見えるが、詳しく調べてみると、まず 2 つのフレームワークの目的が異なることを認識しなければ、公平に比較することはできないことがわかる。Sun のドキュメントにあるように、Collections が Sun 独自の API (コア API、拡張機能など) を均質化するのであれば、Collections は明らかに素晴らしいニュースであり、最も熱狂的な JGL 中毒者にとっても良いものであるはずだ。Sun がこの分野で約束を破らない限り、私は喜んでリソースを投入して Collections を本格的に採用するつもりだ。
注: J2SE 5.0 のリリースに伴い、このパッケージはメンテナンスモードに入ります。重要な修正のみがリリースされます。J2SE5 パッケージ java.util.concurrent には、このパッケージの主要コンポーネントの改良された、より効率的な、標準化されたバージョンが含まれています。