ホームページ  >  記事  >  Java  >  Java コレクション フレームワーク アーキテクチャの詳細

Java コレクション フレームワーク アーキテクチャの詳細

高洛峰
高洛峰オリジナル
2017-01-23 10:37:551688ブラウズ

最近、J2EE の本でコレクション フレームワークについての非常に優れた説明を見つけました。それをフィルタリングして投稿し、オブジェクト コレクションを管理するためのインターフェイスとクラスを提供します。以下は、そのさまざまなコンポーネントの説明です。
Collection インターフェイス
Collection は、オブジェクトのグループ、つまりコレクションの要素を表します。コレクションによっては、同一の要素を許可するものと許可しないものがあります。ある種のものとそうでないものがあります。 Java SDK は Collection を直接継承するクラスを提供しません。Java SDK が提供するクラスはすべて、List や Set など、Collection を継承する「サブインターフェイス」です。 Collection インターフェースを実装するすべてのクラスは、2 つの標準コンストラクターを提供する必要があります。パラメーターなしのコンストラクターは空のコレクションを作成するために使用され、Collection パラメーターを持つコンストラクターは新しいコレクションを作成するために使用されます。この新しいコレクションは、渡されたコレクションと同じです。同じ要素を持っています。後者のコンストラクターを使用すると、ユーザーはコレクションをコピーできます。
コレクション内の各要素をトラバースするにはどうすればよいですか? Collection の実際のタイプに関係なく、コレクション内の各要素に 1 つずつアクセスするために使用できるイテレータを返す iterator() メソッドがサポートされています。一般的な使用法は次のとおりです:

Iterator it = collection.iterator(); // 获得一个迭代子 
while(it.hasNext()) { 
Object obj = it.next(); // 得到下一个元素 
}

Collection インターフェースから派生した 2 つのインターフェースは List と Set です。
List インターフェイス
List は順序付けられたコレクションです。このインターフェイスを使用すると、各要素の挿入位置を正確に制御できます。ユーザーは、Java の配列に似たインデックス (配列の添え字に似たリスト内の要素の位置) を使用して、リスト内の要素にアクセスできます。
以下で説明する Set とは異なり、List では同じ要素を使用できます。
Collection インターフェイスに必要な iterator() メソッドに加えて、List は ListIterator インターフェイスを返す listIterator() メソッドも提供します。標準の Iterator インターフェイスと比較して、ListIterator には追加の add() メソッドやその他のメソッドがあり、次のことが可能です。要素の追加、削除、設定、および前方または後方への移動。
List インターフェイスを実装する一般的なクラスには、LinkedList、ArrayList、Vector、Stack などがあります。
LinkedList クラス
LinkedList は List インターフェースを実装し、null 要素を許可します。さらに、LinkedList は、LinkedList の先頭または末尾に追加の get、remove、および insert メソッドを提供します。これらの操作により、LinkedList をスタック、キュー、または両端キューとして使用できるようになります。
LinkedList には同期メソッドがないことに注意してください。複数のスレッドが同時にリストにアクセスする場合、スレッド自体がアクセス同期を実装する必要があります。解決策の 1 つは、リストの作成時に同期されたリストを構築することです。
List list = Collections.synchronizedList(new LinkedList(...));
ArrayList クラス
ArrayList は可変サイズの配列を実装します。 null を含むすべての要素が許可されます。 ArrayList は同期されていません。
size、isEmpty、get、set メソッドの実行時間は一定です。ただし、add メソッドのコストは償却定数であり、n 個の要素を追加するには O(n) 時間がかかります。他の方法では実行時間が直線的になります。
各 ArrayList インスタンスには容量 (Capacity) があり、これは要素を格納するために使用される配列のサイズです。この容量は、新しい要素が追加されると自動的に増加しますが、増加アルゴリズムは定義されていません。多数の要素を挿入する必要がある場合は、挿入前に ensureCapacity メソッドを呼び出して ArrayList の容量を増やし、挿入効率を向上させることができます。
LinkedList と同様に、ArrayList も非同期です。
Vector クラス
Vector は ArrayList に非常に似ていますが、Vector は同期されます。 Vector で作成された Iterator は ArrayList で作成された Iterator と同じインターフェイスを持ちますが、Vector は同期されているため、Iterator が作成されて使用されると、別のスレッドによって Vector の状態が変更されます (たとえば、要素の追加や削除など)。 , Iterator メソッドを呼び出すと ConcurrentModificationException がスローされるため、例外をキャッチする必要があります。
Stack クラス
Stack は Vector を継承し、後入れ先出しスタックを実装します。 Stack には、Vector をスタックとして使用できるようにする 5 つの追加メソッドが用意されています。基本的なプッシュ メソッドとポップ メソッド、およびピーク メソッドはスタックの先頭にある要素を取得し、空のメソッドはスタックが空かどうかをテストし、検索メソッドはスタック内の要素の位置を検出します。スタックは、作成後の空のスタックです。
Set インターフェイス
Set は、重複する要素を含まない Collection です。つまり、任意の 2 つの要素 e1 と e2 には e1.equals(e2)=false があり、Set には最大 1 つの null 要素があります。
明らかに、Set コンストラクターには、渡された Collection パラメーターに重複した要素を含めることができないという制約があります。
注意: 可変オブジェクトは注意して扱う必要があります。 Set 内の可変要素の状態が変化して Object.equals(Object)=true になると、いくつかの問題が発生します。
Map インターフェイス
Map は Collection インターフェイスを継承しないことに注意してください。キーと値のマッピングは提供されません。マップに同じキーを含めることはできず、各キーは 1 つの値のみをマップできます。 Map インターフェイスは、3 種類のセット ビューを提供します。Map のコンテンツは、キー セットのセット、値セットのセット、またはキーと値のマッピングのセットと見なすことができます。
Hashtableクラス
HashtableはMapインターフェースを継承し、キーと値のマッピングのハッシュテーブルを実装します。 null 以外の任意のオブジェクトをキーまたは値として使用できます。
データを追加するには put(key, value) を使用し、データを削除するには get(key) を使用します。これら 2 つの基本操作の時間コストは一定です。
ハッシュテーブルは、初期容量と負荷率という 2 つのパラメーターを通じてパフォーマンスを調整します。通常、デフォルトの負荷係数 0.75 を使用すると、時間と空間のバランスがより良くなります。負荷率を増やすとスペースを節約できますが、それに対応する検索時間が増加し、get や put などの操作に影響します。
ハッシュテーブルを使用する簡単な例は次のとおりです。ハッシュテーブルに 1、2、および 3 を入力します。それぞれのキーは「1」、「2」、「3」です。

Hashtable numbers = new Hashtable(); 
numbers.put(“one”, new Integer(1)); 
numbers.put(“two”, new Integer(2)); 
numbers.put(“three”, new Integer(3));

要取出一个数,比如2,用相应的key: 
Integer n = (Integer)numbers.get(“two”); 
System.out.println(“two = ” + n); 
由于作为key的对象将通过计算其散列函数来确定与之对应的value的位置,因此任何作为key的对象都必须实现hashCode和equals方法。hashCode和equals方法继承自根类Object,如果你用自定义的类当作key的话,要相当小心,按照散列函数的定义,如果两个对象相同,即obj1.equals(obj2)=true,则它们的hashCode必须相同,但如果两个对象不同,则它们的hashCode不一定不同,如果两个不同对象的hashCode相同,这种现象称为冲突,冲突会导致操作哈希表的时间开销增大,所以尽量定义好的hashCode()方法,能加快哈希表的操作。 
如果相同的对象有不同的hashCode,对哈希表的操作会出现意想不到的结果(期待的get方法返回null),要避免这种问题,只需要牢记一条:要同时复写equals方法和hashCode方法,而不要只写其中一个。 
Hashtable是同步的。 
HashMap类 
HashMap和Hashtable类似,不同之处在于HashMap是非同步的,并且允许null,即null value和null key。,但是将HashMap视为Collection时(values()方法可返回Collection),其迭代子操作时间开销和HashMap的容量成比例。因此,如果迭代操作的性能相当重要的话,不要将HashMap的初始化容量设得过高,或者load factor过低。 
WeakHashMap类 
WeakHashMap是一种改进的HashMap,它对key实行“弱引用”,如果一个key不再被外部所引用,那么该key可以被GC回收。 
总结 
如果涉及到堆栈,队列等操作,应该考虑用List,对于需要快速插入,删除元素,应该使用LinkedList,如果需要快速随机访问元素,应该使用ArrayList。 
如果程序在单线程环境中,或者访问仅仅在一个线程中进行,考虑非同步的类,其效率较高,如果多个线程可能同时操作一个类,应该使用同步的类。 
要特别注意对哈希表的操作,作为key的对象要正确复写equals和hashCode方法。 
尽量返回接口而非实际的类型,如返回List而非ArrayList,这样如果以后需要将ArrayList换成LinkedList时,客户端代码不用改变。这就是针对抽象编程。

更多java集合框架的体系结构详细说明相关文章请关注PHP中文网!

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。