ハッシュマップ、ハッシュセット、ツリーマップ、およびツリーセットの同じ要素をJavaで判断するためのいくつかの方法の比較
1.1ハッシュマップ
まず、Hashmapに要素がどのように保存されるかを見てみましょう。マップに保存されている各要素は、キー値のようなキー値ペアであり、PUTメソッドを介して追加されます。さらに、同じキーには、マップ内の値のみが関連付けられます。 PUTメソッドは、次のようにマップで定義されています。
v put(k key、v value);
Key-Valueなどのキー価値ペアを保存するために使用されます。返品値は、キーによってマップに保存されている古い値です。それが以前に存在しない場合、それはnullを返します。これは、HashMap Putメソッドの実装方法です。
public v put(k key、v value){if(key == null)return putfornullkey(value); int hash = hash(key); int i = indexfor(hash、table.length); for(entry <k、v> e = table [i]; e!= null; e = e.next){object k; if(e.hash == hash &&((k = e.key)== key || key.equals(k)){v oldvalue = e.value; e.value = value; E.RecordAccess(This); OldValueを返します。 }} modcount ++; Addentry(Hash、Key、Value、I); nullを返します。 }上記から、対応するキー値の組み合わせを追加すると、対応するキーが既に存在する場合、対応する値が直接変更され、古い値が返されることがわかります。キーが存在するかどうかを判断するとき、キーのハッシュコードが最初に比較され、次にキーのハッシュコードが等しいまたは等しいものと比較されます。ここで見ることができないかもしれません。上記のコードから、map.entryのハッシュコードとキーのハッシュコードを比較します。実際、そのmap.entryハッシュコードが実際にそのキーのハッシュコードであることがわかります。対応するキーが元々存在しない場合、Addentryが呼び出され、対応するキー価値がマップに追加されます。 Addentryによって渡されるパラメーターハッシュは、キーに対応するハッシュコードです。次に、Addentryのメソッド定義を見てみましょう。
void addentry(int hash、k key、v value、int bucketindex){if((size> = threshold)&&(null!= table [backetindex])){resize(2 * table.length); hash =(null!= key)?ハッシュ(キー):0; BucketIndex = indexfor(hash、table.length); } createentry(hash、key、value、bucketindex); } void createentry(int hash、k key、v value、int backetindex){entry <k、v> e = table [bucketindex];表[BucketIndex] = new entry <>(hash、key、value、e);サイズ++; }Addentryのコアは、CreateEntryを呼び出してMap.entryオブジェクトを作成し、対応するキー価値を表し、保存することです。明らかに、上記の表はmap.entryの配列です。 Map.Entryは、プロパティハッシュを使用して、対応するキーのハッシュコードを保存します。 Map.entryのコンストラクターを上記でお見せしましょう。
entry(int h、k k、v v、entry <k、v> n){value = v; next = n; key = k;ハッシュ= h; }明らかに、対応するキー、値、キーに対応するハッシュコードを保存します。
HashMapが要素をどのように保存するかを理解した後、Hashmapがどのように要素を保存するかを簡単に確認できます。 HashMapには、要素が同じかどうかを判断するための2つの主要な方法があります。 1つは、キーが同じかどうかを判断することであり、もう1つは値が同じかどうかを判断することです。実際、HashMapが要素をどのように保存するかを導入するとき、HashMapが要素キーが同じかどうかを決定する方法を導入しました。つまり、まず第一に、ハッシュコードは同じであり、第二に、キーは等しいか等しいです。マップでキーが同じであるかどうかの決定は、ContainsKey()メソッドを介して実行され、ハッシュマップでのその実装は次のとおりです。
public boolean containskey(object key){return getEntry(key)!= null; }最終エントリ<k、v> getEntry(オブジェクトキー){int hash =(key == null)? 0:ハッシュ(キー); for(entry <k、v> e = table [indexfor(hash、table.length)]; e!= null; e = e.next){object k; if(e.hash == hash &&((k = e.key)== key ||(key!= null && key.equals(k)))return e; } nullを返します。 }キーのハッシュコードが同じかどうかを最初に決定し、キーが等しいか等しいかを決定することは明らかです。
MAPで使用される値はContainsValueメソッドで審査され、HashMapでのその実装は次のとおりです。
public boolean containsvalue(object value){if(value == null)return containsnullvalue(); entry [] tab = table; for(int i = 0; i <tab.length; i ++)for(entry e = tab [i]; e!= null; e = e.next)if(value.equals(e.value))true; falseを返します。 }明らかに、非ヌル形式の値は値の等しいものによって判断され、null形式は等しい限り、つまり保存された要素の値はnullです。
1.2ハッシュセット
HashMapが要素をどのように保存し、要素が同じかどうかを判断した後、Hashsetが要素が同じかどうかをどのように決定するかを確認するのが簡単です。
ハッシュセットの要素は、実際にはハッシュマップによって保存されます。各ハッシュセットオブジェクトは、対応するハッシュマップオブジェクトへの参照を保持します。ハッシュセットに要素を追加および削除すると、保持するハッシュマップを介して実行されます。要素を保存すると、保持されているハッシュマップの鍵として対応する要素を保存します。対応する値は一定のオブジェクトであるため、保存するときに、要素が同じかどうかを決定する論理を使用します。要素が含まれているかどうかを判断するとき、判断を下すために保持されているハッシュマップのcontainskeyメソッドも呼び出します。
public boolean contains(object o){returnmap.containskey(o); }興味のある友人は、ハッシュセットのソースコードをチェックできます。
1.3 Treemap
Treemapに保存されている要素は、キーに従って順序付けられ、ソートされます。 Treemapには、保存された要素をソートする2つの方法があります。 1つは、保持するコンパレータを並べ替えることであり、もう1つは、同等のインターフェイスを実装するキーを並べ替えることです。最初の方法が推奨されます。保持されているコンパレータ(デフォルトはnull)がnullである場合、2番目の方法が使用されます。 Treemapにはいくつかのコンストラクターがあり、それを通してそれが保持するコンパレータを初期化できます。まず、Treemapが要素を救う方法を見てみましょう。 PUTメソッドは次のように実装されます。
public v put(k key、v value){entry <k、v> t = root; if(t == null){compare(key、key); //タイプ(および可能なnull)root = new entry <>(key、value、null);サイズ= 1; modcount ++; nullを返します。 } int cmp;エントリ<k、v>親; //コンパレータと比較可能なパスコンパレータ<? Super K> CPR = Comparator; if(cpr!= null){do {parent = t; cmp = cpr.compare(key、t.key); if(cmp <0)t = t.left; elseif(cmp> 0)t = t.right;それ以外の場合は、t.setValue(value)を返します。 } while(t!= null); } else {if(key == null)thrownew nullpointerexception();同等の<? Super K> k =(comparable <?super k>)key; {parent = t; cmp = k.compareto(T.Key); if(cmp <0)t = t.left; elseif(cmp> 0)t = t.right;それ以外の場合は、t.setValue(value)を返します。 } while(t!= null); } entry <k、v> e = new entry <>(key、value、parent); if(cmp <0)parent.left = e; else parent.right = e; fixafterinsertion(e);サイズ++; modcount ++; nullを返します。 }上記の実装から、最初の要素が直接保存されることがわかります。次の要素は2つの状況に分けられます。1つは、保持されているコンパレータが空ではなく、もう1つは保持されているコンパレータが空である場合です。コンパレータが空でない場合、コンパレータは保存された要素の位置を決定します。重要なことの1つは、既存の要素のキーを現在の保存要素のキーと比較した結果が0である場合、現在保存されている要素のキーが元のマップに既に存在し、元のキーに対応する値が新しい値に変更され、古い値が直接返されることです。保持されているコンパレータが空の場合、要素の位置は、比較可能なインターフェイスを実装するキーの比較方法によって決定されます。コンパレータを使用することに似たことの1つは、元のキーが新しく保存されたキーと比較されると、新しく保存されたキーが元のマップに既に存在し、対応する元のキーの値が直接変更され、キー値ペアが保存されなくなることです。実際、要素が存在するかどうかを決定するContainsKeyメソッドの主な実装ロジックは類似しており、特定の実装は次のとおりです。
public boolean containskey(object key){return getEntry(key)!= null; }最終エントリ<k、v> getEntry(オブジェクトキー){//パフォーマンスのためのオフロードコンパレータベースのバージョン(Comparator!= null)return getEntryUsingComparator(key); if(key == null)nullpointerexception();同等の<? Super K> k =(comparable <?super k>)key;エントリ<k、v> p = root; while(p!= null){int cmp = k.compareto(p.key); if(cmp <0)p = p.left; elseif(cmp> 0)p = p.right;それ以外の場合はpを返します。 } nullを返します。 }要素が存在するかどうかを判断するTreeMapのロジックは、比較または比較可能な後の結果が0であるかどうかを判断することであるため、TreeMapを使用して要素の等しいものと同様のロジックを実装する場合、特に注意する必要があります。
Treemapの論理は、対応する値が等しいかどうかを判断することです。ハッシュマップに似ています。興味のある友達は、ソースTreemapコードを確認できます。
1.4ツリーセット
ツリーセットはセットの実装でもあります。保存されている要素は繰り返されず、注文されます。デフォルトでは、格納されている要素は、同等のインターフェイスを実装する必要があります。デフォルトでは、要素が比較可能なオブジェクトとして比較されるためです。ツリーセットは、コンパレータを介して保存されている要素を比較するためにも使用できます。これは、Treesetを構築するときにコンパレータオブジェクトまたはコンパレータオブジェクトを保持するツリーラップを渡すことで実現できます。ツリーセットの実装は、ハッシュセットの実装に似ています。また、マップへの参照も保持していますが、ハッシュマップを参照するのではなく、Treemapです。ツリーセットの要素の追加と削除はすべて、それらが保持しているTreemapによって実装されます。したがって、ハッシュセットと同様に、ツリーセットの要素が同じであるかどうかを判断する方法は、Treemapと同じであり、従来の等しい方法ではなく、コンパレータまたは比較可能なものによっても決定されます。興味のある友達は、ツリーセットのソースコードを確認できます。
読んでくれてありがとう、私はそれがあなたを助けることができることを願っています。このサイトへのご支援ありがとうございます!