Java マップ インターフェイスとは
Java Map インターフェースは Java Collection フレームワークの一部ですが、Collection インターフェースのサブタイプではありません。したがって、リストや他のコレクション オブジェクトとは異なる動作をします。Map<Key, Value> の各要素は、キーと値のペアを表します。Key と value はどちらもオブジェクトです。特定のマップ内のすべてのキーは一意ですが、値は一意ではないため、重複する可能性があります。Java の Map は、独自のインデックスを使用してあらゆるアイテムを検索できる、一種の辞書やオンライン ショップ カタログのようなものだと考えるかもしれません。キーは、マップ内の値の一意の識別子です。たとえば、Map<String, Items> では、文字列はオンライン ショップのアイテムの ID です。
ドキュメントによると、Map には次のサブインターフェイスがあります。
バインディング;
- ConcurrentMap<K,V> ;
- ConcurrentNavigableMap<K,V> ;
- LogicalMessageContext ;
- メッセージコンテキスト;
- NavigableMap<K,V> ;
- SOAPMessageContext ;
- SortedMap<K,V>。
そしてクラスを実装します:
- 抽象地図
- 属性
- 認証プロバイダー
- 同時ハッシュマップ
- 同時スキップリストマップ
- EnumMap
- ハッシュマップ
- ハッシュ表
- アイデンティティハッシュマップ
- リンクされたハッシュマップ
- プリンターの状態の理由
- プロパティ
- プロバイダー
- レンダリングのヒント
- シンプルバインディング
- 表形式データのサポート
- ツリーマップ
- UIデフォルト
- ウィークハッシュマップ
- Java AbstractMap は、Map インターフェイスの大部分を実装する抽象クラスです。
- Java HashMap は、ハッシュ テーブルを使用してキーと値のペアを格納するためのデータ構造です。
- Java TreeMapはツリーを利用する、つまりソートされたキーで表示するためのデータ構造です。
- WeakHashMap は弱いキーを持つハッシュ テーブルを使用し、使用されなくなった場合にガベージ コレクターによって削除できる値で表示します。
- LinkedHashMapは要素を追加する順序を持つマップであり、挿入順序で反復できます。
- EnumMap は、列挙キーで使用するためにAbstractMapクラスを拡張します。
IdentityHashMap は、ドキュメントを比較するときに参照等価性チェックを使用し、
equals()メソッド の代わりに
==操作を使用して比較されるキーとマッピングします。
ここでは、Map Interface の最も一般的な実装である HashMap、TreeMap、LinkedHashMap に注目します。ちなみに、マップ要素の順序は特定の実装に依存します。たとえば、TreeMap と LinkedHashMap には要素の順序が予測可能ですが、HashMap には予測可能ではありません。
マップメソッド
マップの主な操作は、要素の挿入、削除、検索です。
- public Object put(Object key, Object value) は、マップに要素を挿入します。
- public void putAll(Map map) は、指定されたマップをマップ内に挿入します。
- public Object Remove(Object key) は、指定されたキーに従ってエントリを削除します。
- public Object get(Object key) は、指定されたキーの値を返します。
- public boolean containsKey(Object key) は、このマップから指定されたキーを検索します
- public Set keySet() は、すべてのキーを含む Set ビューを返します。
- public SetentrySet() は、すべてのキーと値を含む Set ビューを返します。
ハッシュマップとは
ハッシュマップとは何ですか? これは、Map<Key,Value> インターフェイスの最も一般的な実装です。このデータ構造はハッシュ原理に基づいています。
HashMap の動作の主原則: ハッシュ化
ハッシュマップとは何か、そしてそれがどのように機能するかを理解するために、まずハッシュとハッシュ関数について話しましょう。ハッシュ関数は、数学的な意味での単なる関数です。したがって、何らかの入力値 (オブジェクト、データ) があり、関数は適切なルールを使用してそれを出力値 (ハッシュ) に変換します。多くの場合、ハッシュは適切な長さの 16 進数です。変換プロセスのルールは異なる場合がありますが、次の原則に従います。
- 特定の入力 (オブジェクト) には特定のハッシュ コードがあります。
- 2 つのオブジェクトが等しい場合、それらのハッシュ コードも等しくなります。逆は当てはまりません。
- ハッシュ コードが異なる場合、オブジェクトは明らかに等しくありません。
- 場合によっては、異なるオブジェクトが同じハッシュ コードを持つことがあります。これは「衝突」と呼ばれる非常にまれなイベントであり、高品質のハッシュ関数により衝突の可能性が最小限に抑えられます。
Java では、すべてのオブジェクトにハッシュ コードがあります。すべての Java オブジェクトの親クラスである Object クラスの hashCode メソッドによって計算されます。通常、開発者は、独自のクラスのこのメソッドと、それに関連付けられた
equalsメソッドをオーバーライドします。
HashMap: 仕組み
したがって、すべての Map 実装はキーと値で構成されるため、クラス HashMap<K,V> になります。ハッシュ原理を使用してキーを保存します。HashMap 内では、キーと値のペアが「バケット」に格納されます。これらのバケットは一緒になって、リンクされたリストの内部配列である「テーブル」を構築します。その初期サイズは 16 です
。。Java の HashMap は、キーのハッシュコードを使用して、キーと値のペアをマッピングするバケットを決定します。 HashMap の注意が必要な機能は、テーブル [] の各セル (バケット) が 1 つのペアだけではなく、複数のペアを保持していることです。これらは、明示的なオブジェクト (LinkedList など) としてではなく、暗黙的なチェーンとして保存されます。チェーンは、各ペアが次のペアへのリンクを保存するために作成されます。つまり、すべての HashMap ペアが 16 のチェーンに分散されています。新しいペアをテーブルに追加すると、キーのハッシュが考慮されます。このハッシュは、キー オブジェクトに組み込まれたハッシュコード関数ではありません。0 ~ 15 の範囲であると考えられます。ペアは、ハッシュ インデックスとともにバケットに保存されているペアのチェーンに追加されます。このアプローチにより、検索が高速化されます。キーによってペアを検索するときに、テーブル全体を検索する必要はありません。キーのハッシュが考慮され、ハッシュ インデックスを持つセルに格納されているチェーンのみがチェックされます。HashMap 内のペアが多すぎると、チェーンが長くなりすぎます。その後、配列のサイズが増加し、保存されているすべてのオブジェクトのハッシュが再計算され、新しいチェーンに沿って分散されます。
ハッシュマップ宣言
クラス HashMap コードに移動すると、次の宣言が見つかります。
public class HashMap extends AbstractMap implements Map, Cloneable, Serializable
ここで、
Kはこのマップによって維持されるキーのタイプ、
Vはマップされた値のタイプです。これは、コード内で整数キーと文字列値を使用した HashMap 宣言の例です。
HashMap<Integer, String> myHashMap = new HashMap<Integer, String>();
HashMap メソッド
HashMap メソッドのリストは次のとおりです。
- Object get(Object key) は、指定されたキーの値を返します。
- オブジェクト put(Key k, Value v) は、キー値マッピングをマップに挿入します。
- Object Remove(Object key) は、指定されたキーのマッピングが存在する場合、このマップからマッピングを削除します。
- void clear() は、 HashMap からすべてのキーと値のペアを削除します。
- Object clone() は、キーと値のクローンを作成せずに、この HashMap インスタンスの浅いコピーを返します。
- boolean containsKey(Object key) は、指定されたキーがマップ内で見つかった場合は true を返し、そうでない場合は false を返します。
- boolean containsValue(Object Value) は、指定されたキーがマップ内で見つかった場合は true、そうでない場合は false を返します。
- boolean isEmpty() は、マップが空の場合は true を返し、そうでない場合は false を返します。
- Set keySet() は、マップから取得したキーのセットを返します。
- int size()はキーと値のマッピングの量を返します。
- Collection value()は、マップの値のコレクションを返します。
- Object Remove(Object key) は、指定されたキーのキーと値のペアを削除します。
- void putAll(Map m) は、マップのすべての要素を他のマップにコピーします。
Java ハッシュマップの例
Java HashMap の例を使用してプログラムを作成して、どのように機能するかを示してみましょう。
import java.util.HashMap;
import java.util.Map;
import java.util.Iterator;
import java.util.Set;
public class HashMap {
public static void main(String[] args) {
{
// HashMap declaration
HashMap<Integer, String> myHashMap = new HashMap<Integer, String>();
//Adding elements into HashMap
myHashMap.put(7, "Johnny");
myHashMap.put(8, "Ivy");
myHashMap.put(1, "Rick");
myHashMap.put(4, "Stan");
myHashMap.put(3, "Kyle");
//print out the map content using Iterator
Set set = myHashMap.entrySet();
Iterator iterator = set.iterator();
while (iterator.hasNext()) {
Map.Entry mapEntry = (Map.Entry) iterator.next();
System.out.print("key: " + mapEntry.getKey() + " value: ");
System.out.println(mapEntry.getValue());
}
System.out.println("get an element from myHashMap via key and print the value out:");
System.out.println(myHashMap.get(8));
//print out hashMap on standard way:
System.out.println(myHashMap);
// Get values based on key
String var = myHashMap.get(2);
//here we'll get null, we don't have such a key
System.out.println("Value with key 2: " + var);
var = myHashMap.get(7);
System.out.println("Value with key 7: " + var);
// Remove values based on key
myHashMap.remove(4);
System.out.println("myHashMap after removing element:");
System.out.println(myHashMap);
myHashMap.clear();
System.out.println("myHashMap after total clearing:");
System.out.println(myHashMap);
}
}
}
プログラムを実行した結果:
key: 1 value: Rick
key: 3 value: Kyle
key: 4 value: Stan
key: 7 value: Johnny
key: 8 value: Ivy
get an element from myHashMap via key and print the value out:
Ivy
{1=Rick, 3=Kyle, 4=Stan, 7=Johnny, 8=Ivy}
Value with key 2: null
Value with key 7: Johnny
myHashMap after removing element:
{1=Rick, 3=Kyle, 7=Johnny, 8=Ivy}
myHashMap after total clearing:
{}
ツリーマップ
Java の TreeMap も Map<Key,Value> インターフェイスを実装しますが、これは Red-Black ツリー データ構造に基づいています。ツリーは「ノード」と、ノード間を結ぶ線「枝」で構成されます。「ルート」ノードはツリーの最上位にあり、ルートから枝やノードが存在します。階層構造になっていると考えるとよいでしょう。これらのノードはルートの「子」として扱われます。子ノードは独自の子、つまり下位ノードを持つことができます。子のないノードは「エンドノード」または「葉」と呼ばれます。バイナリ ツリーは、すべてのノードが 0、1 を持つツリーです。二分探索ツリーは構造であり、すべての内部ノードがキーと、場合によっては関連する値を格納し、2 つの区別できるサブツリー (「左」と「右」) を持ちます。自己平衡型二分探索ツリーは、任意の項目の挿入と削除に直面しても、その高さ (ルートの下の最大レベル数) を自動的に低く保つノードベースの二分探索ツリーです。赤黒ツリーは、次の特性を持つバランスの取れた二分木です。
- すべてのノードは赤または黒のいずれかです
- 根元はいつも黒い
- すべてのリーフは NIL (空、null の一種) ノードであり、黒色です。
- ノードが赤の場合、その子は間違いなく黒です。
- ノードから子孫のリーフまでのすべての単純なパスには、同じ数の黒いノードが含まれます。
ツリーマップの機能
TreeMap は、ツリー データ構造を使用してキーをノードとして保存し、Red-Black Tree アルゴリズムを使用してキーを並べ替えます。したがって、TreeMap は、キーの自然な順序に従ってエントリをソートしたままにします。数値の場合は自然昇順、文字列の場合はアルファベット順です。順序付けのロジックを変更する必要がある場合は、コンパレータを使用できます。オブジェクトを自然な方法で並べ替えることは、さまざまなフィルターや条件を使用してオブジェクトを検索できることと同様に、TreeMap の大きな利点です。
TreeMap メソッド
- Object get(Object key) は、対応するキーの値を返します。
- Object put(Object key, Object value) は、マップにマッピングを挿入します。
- Object Remove(Object key) は、 TreeMap にこのキーが含まれている場合、このキーのマッピングを削除します。
- boolean containsKey(Object key) は、このマップに指定されたキーのマッピングが含まれている場合は true を返します。
- boolean containsValue(Object value) は、 TreeMap が 1 つ以上のキーを指定された値にマップする場合は true を返します。
- オブジェクト firstKey() は、ソートされたマップに現在ある最初のキーを返します。
- オブジェクト lastKey() は、ソートされたマップ内に現在ある最後のキーを返します。
- void putAll(Map map) は、指定されたマップからマップにすべてのマッピングをコピーします。
- SetentrySet() はマッピングのセットビューを返します。
- int size()はキーと値のマッピングの量を返します。
- Collection value() は、値のコレクション ビューを返します。
- Object clone()は TreeMap の浅いコピーを返します。
- void clear() は、 TreeMap からすべてのマッピングを削除します。
- SortedMap headMap(Object key_value) は、パラメータ key_value より小さいマップ部分のビューを返します。
- Set keySet() は、ツリーマップに含まれるキーの Set ビューを返します。
- SortedMap subMap(K fromKey, K toKey) は、キーが fromKey (両端を含む) から toKey (両端を含まない) までの範囲にあるこのマップの部分のビューを返します。
- オブジェクト firstKey() は、 TreeMap から最初のキーを返します。
ツリーマップの例
import java.util.TreeMap;
import java.util.Set;
import java.util.Iterator;
import java.util.Map;
public class TreeMapExample {
public static void main(String args[]) {
//TreeMap declaration
TreeMap<Integer, String> myTreeMap = new TreeMap<Integer, String>();
//put elements to TreeMap
myTreeMap.put(1, "Stuart");
myTreeMap.put(23, "Michael");
myTreeMap.put(7, "Johnny");
myTreeMap.put(5, "Ivy");
myTreeMap.put(2, "Alex");
//Display and print out myTreeMap using Iterator
Set set = myTreeMap.entrySet();
Iterator iterator = set.iterator();
while (iterator.hasNext()) {
Map.Entry myEntry = (Map.Entry) iterator.next();
System.out.print("key: " + myEntry.getKey() + " value: ");
System.out.println(myEntry.getValue());
}
//TreeMap printed in classical way
System.out.println(myTreeMap);
//removing an element with the key =2
myTreeMap.remove(2);
//myTreeMap after removing:
System.out.println(myTreeMap);
}
}
プログラムを実行した結果:
key: 1 value: Stuart
key: 2 value: Alex
key: 5 value: Ivy
key: 7 value: Johnny
key: 23 value: Michael
{1=Stuart, 2=Alex, 5=Ivy, 7=Johnny, 23=Michael}
{1=Stuart, 5=Ivy, 7=Johnny, 23=Michael}
リンクされたハッシュマップ
LinkedHashMap は、リンク リストとハッシュ マップを組み合わせたデータ構造です。確かに、LinkedHashMap は HashMap クラスを拡張し、Map インターフェイスを実装しますが、リンク リストについてはどうなるのでしょうか? LinkedHashMap の宣言:
Map <Integer, String> linkedHashMap = new LinkedHashMap <Integer, String>();
この新しい linkedHashMap は、HashMap からプロパティ (table、loadFactor、threshold、size、entrySet など) を継承し、次の 2 つの特別なプロパティも取得します。
- header は二重リンクリストの先頭です。初期化中に、それ自体を示します
- accessOrder は、イテレータを使用して要素にアクセスする方法を示します。true の場合、最後のアクセスの順。false の場合、アクセスは要素が挿入された順序で行われます。
このリンク リストは反復順序を定義します。通常、これはマップにキーを挿入する順序です。
LinkedHashMap メソッド
- Object get(Object key) は、指定されたキーがマップされている値を返します。このマップにキーのマッピングが含まれていない場合は null を返します。
- void clear() は、マップからすべてのマッピングを削除します。
- boolean containsKey(Object key) は、指定された要素が 1 つ以上のキーによってマップされている場合に true を返します。
- boolean RemoveEldestEntry(Map.Entry最長)は、マップがマップから最も古いエントリを削除する場合にtrueを返します。
- Set<Map.Entry<K,V>>entrySet() は、このマップに含まれるマッピングの Set ビューを返します。
- void forEach(BiConsumer<? super K,? super V> action) は、すべてのエントリが処理されるか、アクションが例外をスローするまで、このマップ内の各エントリに対して指定されたアクションを実行します。
- Object getOrDefault(Object key, VdefaultValue) は、指定されたキーがマップされる値を返します。マップにキーのマッピングが含まれていない場合は、defaultValue が返されます。
- Set<K> keySet() は、マップに含まれるキーの Set ビューを返します。
- boolean RemoveEldestEntry(Map.Entry<K,V>長男) は、このマップが最も古いエントリを削除する必要がある場合に true を返します。
- void replaceAll(BiFunction<? super K,? super V,? extends V> function) は、すべてのエントリが処理されるか関数が例外をスローするまで、各エントリの値をそのエントリに対して指定された関数を呼び出した結果に置き換えます。
- Collection<v>values() は、マップに含まれる値のコレクション ビューを返します。
LinkedHashMap の例
import java.util.LinkedHashMap;
import java.util.Set;
import java.util.Iterator;
import java.util.Map;
public class HashLinkedListExample {
public static void main(String args[]) {
// LinkedHashMap Declaration
LinkedHashMap<Integer, String> myLinkedHashMap =
new LinkedHashMap<Integer, String>();
//Adding elements into LinkedHashMap
myLinkedHashMap.put(7, "Johnny");
myLinkedHashMap.put(12, "Rick");
myLinkedHashMap.put(1, "Kyle");
myLinkedHashMap.put(5, "Percy");
myLinkedHashMap.put(85, "Sebastian");
// Generate a Set of entries
Set set = myLinkedHashMap.entrySet();
// Display and print out the nodes of LinkedHashMap
Iterator iterator = set.iterator();
while(iterator.hasNext()) {
Map.Entry me = (Map.Entry)iterator.next();
System.out.print("key: "+ me.getKey() +
" value: "+me.getValue()+"\n");
}
//print out HashLinkedMap on standard way:
System.out.println(myLinkedHashMap);
myLinkedHashMap.put(21, "Ivy");
System.out.println(myLinkedHashMap);
myLinkedHashMap.remove(12);
System.out.println(myLinkedHashMap);
myLinkedHashMap.put(12, "Ronny");
System.out.println(myLinkedHashMap);
myLinkedHashMap.put(1, "Stan");
System.out.println(myLinkedHashMap);
}
}
ここでは、5 つの要素を追加して新しい LinkedHashMap を作成し、イテレータを使用して従来の方法で出力します。ご覧のとおり、LinkedHashMap は挿入順序を維持します。その後、マップから要素を削除し、新しい要素を追加します。その後、キーを持つ要素がもう 1 つ追加されます。これはすでにマップ上にあります。このキーにマップされている古い値を置き換えます。
プログラムを実行した結果:
key: 7 value: Johnny
key: 12 value: Rick
key: 1 value: Kyle
key: 5 value: Percy
key: 85 value: Sebastian
{7=Johnny, 12=Rick, 1=Kyle, 5=Percy, 85=Sebastian}
{7=Johnny, 12=Rick, 1=Kyle, 5=Percy, 85=Sebastian, 21=Ivy}
{7=Johnny, 1=Kyle, 5=Percy, 85=Sebastian, 21=Ivy}
{7=Johnny, 1=Kyle, 5=Percy, 85=Sebastian, 21=Ivy, 12=Ronny}
{7=Johnny, 1=Stan, 5=Percy, 85=Sebastian, 21=Ivy, 12=Ronny}
HashMap、TreeMap、LinkedHashMap の比較
HashMap、TreeMap、および LinkedHashMap は、Map インターフェイスの実装です。HashMap と LinkedHashMap は、キーをハッシュするデータ構造です。TreeMap は、キーの自然な順序を使用して検索ツリーを編成します。
注文:
- HashMap は順序を維持しません。
- TreeMap は、キーの昇順でエントリを並べ替えます。
- LinkedHashMap は挿入順序を維持します。
ヌルキー:
- HashMap と LinkedHashMap では、1 つの null キーを持つことができます。
- LinkedHashMap は、キーが自然順序付けを使用している場合、または Comparator が null レイでの比較をサポートしていない場合、null キーを許可しません。
この記事でレビューした 3 つの実装すべてを含む Java マップの例を見てみましょう。
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.TreeMap;
public class CompMapImpl {
public static void main(String[] args) {
HashMap<Integer, String> hashMap = new HashMap<>();
TreeMap<Integer, String> treeMap = new TreeMap<>();
LinkedHashMap<Integer, String> linkedHashMap = new LinkedHashMap<>();
hashMap.put(5, "Ivy");
hashMap.put(null, "Joker");
hashMap.put(1, "First");
hashMap.put(2, "Kyle");
hashMap.put(-2, "Paul");
hashMap.put(3, "Sandy");
treeMap.put(5, "Ivy");
//treeMap.put(null,"Joker");
treeMap.put(1, "First");
treeMap.put(2, "Kyle");
treeMap.put(-2, "Paul");
treeMap.put(3, "Sandy");
linkedHashMap.put(5, "Ivy");
linkedHashMap.put(null, "Joker");
linkedHashMap.put(1, "First");
linkedHashMap.put(2, "Kyle");
linkedHashMap.put(-2, "Paul");
linkedHashMap.put(3, "Sandy");
System.out.println("HashMap");
System.out.println(hashMap);
System.out.println("TreeMap");
System.out.println(treeMap);
System.out.println("LinkedHashMap");
System.out.println(linkedHashMap);
LinkedHashMap<String, String> linkedHashMap1= new LinkedHashMap<> ();
linkedHashMap1.put(null, "Andy");
System.out.println(linkedHashMap1);
}
}
このプログラムを実行した結果は次のとおりです。
HashMap
{null=Joker, 1=First, -2=Paul, 2=Kyle, 3=Sandy, 5=Ivy}
TreeMap
{-2=Paul, 1=First, 2=Kyle, 3=Sandy, 5=Ivy}
LinkedHashMap
{5=Ivy, null=Joker, 1=First, 2=Kyle, -2=Paul, 3=Sandy}
{null=Andy}
ご覧のとおり、HashMap 内の要素の順序は明らかではありません。treeMap ではキーに依存しますが、LinkedHashMap では挿入順序に依存します。linkedHashMap に null キーを入れようとすると NullPointerException が発生しますが、キーが String である linkedHashMap1 ではそれが可能です。ハッシュ マップは、最適な汎用マップ実装です。最大の検索速度、高速なストレージ、および取得操作を提供しますが、その無秩序な順序について覚えておく必要があります。リンクされたハッシュ マップは HashMap の利点を継承し、キーの順序を取得します。ただし、メモリの点で比較的高価な linkedList が含まれています。検索では HashMap よりも遅く、リンクされたリストを維持するため追加/削除では少し遅くなります。ツリー マップには、キーが昇順にソートされて格納されます。しかし、
学んだことをさらに強化するには、Java コースのビデオ レッスンを視聴することをお勧めします。
GO TO FULL VERSION