web-dev-qa-db-ja.com

hashCode()がオーバーライドされていない場合、オブジェクトのハッシュコードは何ですか?

HashCode()メソッドがオーバーライドされていない場合、JavaのオブジェクトでhashCode()を呼び出した結果はどうなりますか?

64
java_geek

通常、コードをオーバーライドしない場合、hashCode()はオブジェクトのアドレスをメモリに返すだけです。

1 から:

合理的に実用的である限り、Objectクラスで定義されたhashCodeメソッドは、個別のオブジェクトに対して個別の整数を返します。 (これは通常、オブジェクトの内部アドレスを整数に変換することによって実装されますが、この実装手法はJavaTMプログラミング言語では必要ありません。)

34
Hans W

HotSpot JVMでは、デフォルトでは、オーバーロードされていないObject.hashCodeまたはSystem.identityHashCodeの最初の呼び出し時に、乱数が生成され、オブジェクトヘッダーに格納されます。 Object.hashCodeまたはSystem.identityHashCodeへのその後の呼び出しは、ヘッダーからこの値を抽出するだけです。デフォルトでは、オブジェクトのコンテンツやオブジェクトの場所と共通するものはなく、乱数のみです。この動作は、以下の可能な値を持つ-XX:hashCode=n HotSpot JVMオプションによって制御されます。

  • 0:グローバルランダムジェネレーターを使用します。これは、Java 7.のデフォルト設定です。これには、複数のスレッドからの同時呼び出しが競合状態を引き起こし、異なるオブジェクトに対して同じhashCodeを生成する可能性があるという欠点があります。競合が原因で遅延が発生する可能性があります(異なるCPUコアの同じメモリ領域を使用)。
  • 5:以前の不利な点のない、スレッド固有のxor-shiftランダムジェネレーターを使用します。これは、Java 8のデフォルト設定です。
  • 1:「stop-the-world」イベントで変更されるランダム値と混合されたオブジェクトポインターを使用します。これにより、stop-the-worldイベント(ガベージコレクションなど)の間に生成されたhashCodeが安定します(テスト/デバッグ用)。
  • 2:常に1を使用(テスト/デバッグ目的で)
  • 3:自動インクリメント番号を使用します(テスト/デバッグの目的で、グローバルカウンターも使用されるため、競合と競合状態が発生する可能性があります)
  • 4:必要に応じて32ビットにトリミングされたオブジェクトポインターを使用します(テスト/デバッグの目的で)

-XX:hashCode=4を設定しても、hashCodeが常にオブジェクトアドレスを指すとは限らないことに注意してください。オブジェクトは後で移動される可能性がありますが、hashCodeは同じままです。また、オブジェクトアドレスの分散が不十分なため(アプリケーションがメモリをあまり使用しない場合、ほとんどのオブジェクトは互いに近くに配置されます)、このオプションを使用すると、ハッシュテーブルのバランスが崩れる可能性があります。

54
Tagir Valeev

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() もオーバーライドする必要があります。

13
Asaph

ハッシュコードがオーバーライドされていない場合は、オブジェクトのハッシュコードを呼び出します。以下は、javadocからの抜粋です。

合理的に実用的である限り、Objectクラスで定義されたhashCodeメソッドは、個別のオブジェクトに対して個別の整数を返します。 (これは通常、オブジェクトの内部アドレスを整数に変換することによって実装されますが、この実装手法はJavaTMプログラミング言語では必要ありません。)

3
pgras

equalsをオーバーライドするすべてのクラスでhashCodeをオーバーライドする必要があります。そうしないと、Object.hashCodeの一般規約に違反し、conjunction with all hash-based collectionsでクラスが正しく機能しなくなります。 、including HashMap, HashSet, and Hashtable.

1
anish

デフォルトのハッシュコード実装は、jvm内のオブジェクトの内部アドレスを32ビット整数として提供します。したがって、2つの異なる(メモリ内の)オブジェクトは異なるハッシュコードを持ちます。

これは、equalsのデフォルトの実装と一致しています。オブジェクトのequalsをオーバーライドする場合、それらが一貫するようにhashCodeを適応させる必要があります。

概要については、 http://www.ibm.com/developerworks/Java/library/j-jtp05273.html を参照してください。

1
tonio

異なるオブジェクトが異なる結果を与えるように、ハッシュコードを実装するようにしてください。これを行う標準的な方法はないと思います。

情報 については、この記事をお読みください。

0
kgiannakakis

ハッシュコードは、ハッシュセットなどのコレクションにオブジェクトを格納するのに役立ちます。オブジェクトがハッシュコードを一意のものとして定義できるようにすることで、HashSetのアルゴリズムが効果的に機能できるようになります。

オブジェクト自体は、メモリ内のオブジェクトのアドレスを使用します。これは非常に一意ですが、2つの異なるオブジェクト(たとえば、2つの同一の文字列)がメモリ内で複製されている場合でも、同じであると見なされる場合はあまり役に立ちません。

0
Yishai

Equals()に関して、ハッシュコードが異なる2つのオブジェクトは等しくない

a.hashCode() != b.hashCode()!a.equals(b)を意味する必要があります

ただし、equals()に関して等しくない2つのオブジェクトは、同じハッシュコードを持つことができます。多くのオブジェクトが同じハッシュコードを持つ場合、これらのオブジェクトをセットまたはマップに格納すると効率が低下します。

0
ndeuma

6桁の16進数を返します。これは通常、オブジェクトがアドレス指定されているスロットのメモリ位置です。アルゴリズム自体から、JDKはオープンアドレッシングに最適なハッシュ関数の1つであるダブルハッシュ(ネイティブ実装)を実行すると思います。このダブルハッシュ方式により、衝突の可能性が大幅に減少します。

次の投稿は支持的な考えを与えるでしょう-

Java-衝突処理とget()メソッドに関するHashMapの混乱

0
Larsen

本当に答えではありませんが、以前のコメントに追加します

オブジェクトの内部アドレスは、ヒープの圧縮中にガベージコレクターがオブジェクトを移動する可能性がある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を実装する方法を誰かに教えてもらえますか?

0
Ustaman Sangat