HashCode()メソッドがオーバーライドされていない場合、JavaのオブジェクトでhashCode()を呼び出した結果はどうなりますか?
通常、コードをオーバーライドしない場合、hashCode()はオブジェクトのアドレスをメモリに返すだけです。
1 から:
合理的に実用的である限り、Objectクラスで定義されたhashCodeメソッドは、個別のオブジェクトに対して個別の整数を返します。 (これは通常、オブジェクトの内部アドレスを整数に変換することによって実装されますが、この実装手法はJavaTMプログラミング言語では必要ありません。)
HotSpot JVMでは、デフォルトでは、オーバーロードされていないObject.hashCode
またはSystem.identityHashCode
の最初の呼び出し時に、乱数が生成され、オブジェクトヘッダーに格納されます。 Object.hashCode
またはSystem.identityHashCode
へのその後の呼び出しは、ヘッダーからこの値を抽出するだけです。デフォルトでは、オブジェクトのコンテンツやオブジェクトの場所と共通するものはなく、乱数のみです。この動作は、以下の可能な値を持つ-XX:hashCode=n
HotSpot JVMオプションによって制御されます。
1
を使用(テスト/デバッグ目的で)-XX:hashCode=4
を設定しても、hashCodeが常にオブジェクトアドレスを指すとは限らないことに注意してください。オブジェクトは後で移動される可能性がありますが、hashCodeは同じままです。また、オブジェクトアドレスの分散が不十分なため(アプリケーションがメモリをあまり使用しない場合、ほとんどのオブジェクトは互いに近くに配置されます)、このオプションを使用すると、ハッシュテーブルのバランスが崩れる可能性があります。
hashCode()
の実装はクラスによって異なる場合がありますが、 hashCode()
の規約は非常に具体的であり、 Javadocs :
オブジェクトのハッシュコード値を返します。このメソッドは、Java.util.Hashtableによって提供されるハッシュテーブルなどの利点のためにサポートされています。
HashCodeの一般的な規約は次のとおりです。
- Javaアプリケーションの実行中に同じオブジェクトで複数回呼び出される場合は常に、オブジェクトの等値比較で使用される情報が変更されない限り、hashCodeメソッドは常に同じ整数を返す必要があります。この整数は、アプリケーションのある実行から同じアプリケーションの別の実行まで一貫性を保つ必要はありません。
- Equals(Object)メソッドに従って2つのオブジェクトが等しい場合、2つのオブジェクトのそれぞれでhashCodeメソッドを呼び出すと、同じ整数の結果が生成される必要があります。
- Equals(Java.lang.Object)メソッドに従って2つのオブジェクトが等しくない場合、2つのオブジェクトのそれぞれでhashCodeメソッドを呼び出すと、異なる整数の結果が生成される必要はありません。ただし、プログラマは、異なるオブジェクトに対して異なる整数の結果を生成すると、ハッシュテーブルのパフォーマンスが向上する可能性があることに注意する必要があります。
合理的に実用的である限り、Objectクラスで定義されたhashCodeメソッドは、個別のオブジェクトに対して個別の整数を返します。 (これは通常、オブジェクトの内部アドレスを整数に変換することによって実装されますが、この実装手法はJavaTMプログラミング言語では必要ありません。)
hashCode()
は equals()
と密接に関連しており、オーバーライドした場合 equals()
、 hashCode()
もオーバーライドする必要があります。
ハッシュコードがオーバーライドされていない場合は、オブジェクトのハッシュコードを呼び出します。以下は、javadocからの抜粋です。
合理的に実用的である限り、Objectクラスで定義されたhashCodeメソッドは、個別のオブジェクトに対して個別の整数を返します。 (これは通常、オブジェクトの内部アドレスを整数に変換することによって実装されますが、この実装手法はJavaTMプログラミング言語では必要ありません。)
equalsをオーバーライドするすべてのクラスでhashCodeをオーバーライドする必要があります。そうしないと、Object.hashCodeの一般規約に違反し、conjunction with all hash-based collection
sでクラスが正しく機能しなくなります。 、including HashMap, HashSet, and Hashtable.
デフォルトのハッシュコード実装は、jvm内のオブジェクトの内部アドレスを32ビット整数として提供します。したがって、2つの異なる(メモリ内の)オブジェクトは異なるハッシュコードを持ちます。
これは、equalsのデフォルトの実装と一致しています。オブジェクトのequalsをオーバーライドする場合、それらが一貫するようにhashCodeを適応させる必要があります。
概要については、 http://www.ibm.com/developerworks/Java/library/j-jtp05273.html を参照してください。
異なるオブジェクトが異なる結果を与えるように、ハッシュコードを実装するようにしてください。これを行う標準的な方法はないと思います。
情報 については、この記事をお読みください。
ハッシュコードは、ハッシュセットなどのコレクションにオブジェクトを格納するのに役立ちます。オブジェクトがハッシュコードを一意のものとして定義できるようにすることで、HashSetのアルゴリズムが効果的に機能できるようになります。
オブジェクト自体は、メモリ内のオブジェクトのアドレスを使用します。これは非常に一意ですが、2つの異なるオブジェクト(たとえば、2つの同一の文字列)がメモリ内で複製されている場合でも、同じであると見なされる場合はあまり役に立ちません。
Equals()に関して、ハッシュコードが異なる2つのオブジェクトは等しくない
a.hashCode() != b.hashCode()
は!a.equals(b)
を意味する必要があります
ただし、equals()に関して等しくない2つのオブジェクトは、同じハッシュコードを持つことができます。多くのオブジェクトが同じハッシュコードを持つ場合、これらのオブジェクトをセットまたはマップに格納すると効率が低下します。
6桁の16進数を返します。これは通常、オブジェクトがアドレス指定されているスロットのメモリ位置です。アルゴリズム自体から、JDKはオープンアドレッシングに最適なハッシュ関数の1つであるダブルハッシュ(ネイティブ実装)を実行すると思います。このダブルハッシュ方式により、衝突の可能性が大幅に減少します。
次の投稿は支持的な考えを与えるでしょう-
本当に答えではありませんが、以前のコメントに追加します
オブジェクトの内部アドレスは、ヒープの圧縮中にガベージコレクターがオブジェクトを移動する可能性があるJVMで変更されないままであることを保証できません。
私はこのようなことをやろうとしました:
public static void main(String[] args) {
final Object object = new Object();
while (true) {
int hash = object.hashCode();
int x = 0;
Runtime r = Runtime.getRuntime();
List<Object> list = new LinkedList<Object>();
while (r.freeMemory() / (double) r.totalMemory() > 0.3) {
Object p = new Object();
list.add(p);
x += object.hashCode();//ensure optimizer or JIT won't remove this
}
System.out.println(x);
list.clear();
r.gc();
if (object.hashCode() != hash) {
System.out.println("Voila!");
break;
}
}
}
しかし、ハッシュコードは実際には変わりません... SunのJDKが実際にObect.hashcodeを実装する方法を誰かに教えてもらえますか?