ytnk531の日記

日々調べたことを書きます。

Object.equals()とObject.hashCode()のデフォルト実装

java.lang.Objectのequals()とhashCode()の実装について調べました。

Object.equals()

JDK 8 での実装は下記の通り、参照値を比較しているだけです。

    public boolean equals(Object obj) {
        return (this == obj);
    }

jdk8u/jdk8u/jdk: a71d26266469 src/share/classes/java/lang/Object.java

参照値とはすなわちオブジェクトへのポインタなので、Object.equals()は同一のインスタンスであるときだけtrueを返します。

The reference values (often just references) are pointers to these objects, and a special null reference, which refers to no object.

参照値(単に参照とも)はオブジェクトへのポインタまたはnullです。nullはオブジェクトを参照しない特殊な参照値です。

Chapter 4. Types, Values, and Variables

Object.hashCode()

hashCode()はJVMの実装に依存します。

srvaroa.github.io

こちらの記事でとても詳しく説明されていました。 結局のところ

  • OpenJDK 8, OpenJDK 9
    • スレッドごとに持つ値をXorshiftした数
  • OpenJDK 7, OpenJDK 6
    • 乱数

とのことでした。 XorShiftは、排他的論理和とビットシフトのみで(高速に)疑似乱数を生成できるアルゴリズムです。 hash codeは一度生成されるとObject Headerと呼ばれるインスタンスごとに持つ領域に記録されます。 二回目以降のhashCode()の呼び出し時には、Object Headerに記録されたhash codeを返します。

OpenJDK8でhash codeを生成するコードは次の通りです。

     // Marsaglia's xor-shift scheme with thread-specific state
     // This is probably the best overall implementation -- we'll
     // likely make this the default in future releases.
     unsigned t = Self->_hashStateX ;
     t ^= (t << 11) ;
     Self->_hashStateX = Self->_hashStateY ;
     Self->_hashStateY = Self->_hashStateZ ;
     Self->_hashStateZ = Self->_hashStateW ;
     unsigned v = Self->_hashStateW ;
     v = (v ^ (v >> 19)) ^ (t ^ (t >> 8)) ;
     Self->_hashStateW = v ;
     value = v ;

jdk8u/jdk8u/hotspot: 87ee5ee27509 src/share/vm/runtime/synchronizer.cpp

スレッドのメンバ変数_hashStateX_hashStateWを使ってハッシュコードを生成します。 xor-shiftのアルゴリズムは理解できていないのですが、hashStateX, hashStateY, hashStateWをアルファベット順で一つ前の名前を持つ変数に値を移し、hashStateWを生成したハッシュコードにすることで、次の呼び出し時にもユニークな値が生成できるようにしています。

_hashStateはスレッド生成時に次のように初期化されます。

  _hashStateX = os::random() ;
  _hashStateY = 842502087 ;
  _hashStateZ = 0x8767 ;    // (int)(3579807591LL & 0xffff) ;
  _hashStateW = 273326509 ;

jdk8u/jdk8u/hotspot: 87ee5ee27509 src/share/vm/runtime/thread.cpp