次のコードを検討してください。
import Java.util.*;
class Employee {
String name;
public Employee(String nm) {
this.name=nm;
}
}
public class HashMapKeyNullValue {
Employee e1;
public void display(){
Employee e2=null;
Map map=new HashMap();
map.put(e2, "25");
System.out.println("Getting the Value When e2 is set as KEY");
System.out.println("e2 : "+map.get(e2));
System.out.println("e1 : "+map.get(e1));
System.out.println("null : "+map.get(null));
map.put(e1, "");
System.out.println("Getting the Value when e1 is set as KEY");
System.out.println("e2 : "+map.get(e2));
System.out.println("e1 : "+map.get(e1));
System.out.println("null : "+map.get(null));
map.put(null, null); // null as key and null as value
System.out.println("Getting the Value when setting null as KEY and null as value");
System.out.println("e2 : "+map.get(e2));
System.out.println("e1 : "+map.get(e1));
System.out.println("null : "+map.get(null));
map.put(null, "30");
System.out.println("Getting the Value when setting only null as KEY");
System.out.println("e2 : "+map.get(e2));
System.out.println("e1 : "+map.get(e1));
System.out.println("null : "+map.get(null));
}
public static void main(String[] args) {
new HashMapKeyNullValue().display();
}
}
プログラムの出力は次のとおりです。
Getting the Value When e2 is set as KEY
e2 : 25
e1 : 25
null : 25
Getting the Value when e1 is set as KEY
e2 :
e1 :
null :
Getting the Value when setting null as KEY and null as value
e2 : null
e1 : null
null : null
Getting the Value when setting only null as KEY
e2 : 30
e1 : 30
null : 30
ここで、キーとしてe1, e2, and null
がどのように相互に関連しているか。 3つすべてが同じハッシュコードに割り当てられていますか?はいの場合、なぜですか?
3つすべてが異なって見えるため、1つの値の変更が他の値を変更します。キーのエントリが1つだけHashMap
またはe1, e2, or null
に作成されるということは、すべて同じキーのように扱われるためです。
HashMap
は、nullがキーおよびnullキーとして渡されたときにハッシュコードを呼び出さない特別なケースとして扱われます。
HashMap
putsnullキーをバケットに0 およびnullを渡された値のキーとしてマップします。 HashMapは、リンクリストデータ構造によってそれを行います。 HashMapは内部でリンクリストデータ構造を使用します。
HashMap
(HashMap.Java
の静的クラス)が使用するリンクリストデータ構造
static class Entry<K,V> implements Map.Entry<K,V> {
final K key;
V value;
Entry<K,V> next;
final int hash;
}
Entryクラスでは、[〜#〜] k [〜#〜]はnullに設定され、値は渡された値にマップされますputメソッド。
Hashmap
getメソッドでは、キーがnullとして渡されるかどうかをチェックします。バケット内のnullキーの検索値。
そのため、1つにnullキーは1つしか存在できませんhashmap
object。
null
をマップキーとして渡すと、0 bucket
。 nullキーのすべての値がそこに行きます。これが同じ値を返す理由です。提供するすべてのキーはnull
であり、HashMapの同じバケットにあります。
null keyの場合、Hashmap実装はそれを特別なケースと見なし、代わりにEntryオブジェクトを0バケットの場所に格納するhashCodeメソッドを呼び出しません。
HashMapにNULLを入力すると、キーとしてNULLを入力しようとしているかどうか(putForNullKey()と呼ばれる)特別なチェックが行われます。これは特殊なケースであり、null以外のオブジェクトを配置しようとするのとは異なり、ハッシュ計算を行わないこともあります。
public V put(K key, V value) {
if (table == EMPTY_TABLE) {
inflateTable(threshold);
}
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);
return oldValue;
}
}
modCount++;
addEntry(hash, key, value, i);
return null;
}
private V putForNullKey(V value) {
for (Entry<K,V> e = table[0]; e != null; e = e.next) {
if (e.key == null) {
V oldValue = e.value;
e.value = value;
e.recordAccess(this);
return oldValue;
}
}
modCount++;
addEntry(0, null, value, 0);
return null;
}
HashMapは、キーごとに1つの値のみを保存できます。より多くの値を保存する場合は、MultivalueHashMapを使用する必要があります(Google GuavaおよびApache Commons Collectionsには、そのようなマップの実装が含まれています)。
e1とe2の値はnullです。オブジェクトを割り当てないためです。したがって、これらの変数を使用すると、そのマップエントリのキーもnullになり、結果が得られます。 Nullにはハッシュコードはありませんが、HashMapのキーとして許容されます(Nullをキーとして許可しない他のMap実装があります)。