LoginSignup
3
4

More than 5 years have passed since last update.

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

Last updated at Posted at 2018-07-14

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

Object.equals()

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

src/share/classes/java/lang/Object.java
    public boolean equals(Object obj) {
        return (this == obj);
    }

src/share/classes/java/lang/Object.java#l149

参照値とはすなわちオブジェクトへのポインタなので、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はオブジェクトを参照しない特殊な参照値です。

JLS 4.3.1

Object.hashCode()

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

share/classes/java/lang/Object.java#l100
public native int hashCode();

share/classes/java/lang/Object.java#l100

下記の記事でとても詳しく説明されています。
How does the default hashCode() work?

結局のところOpenJDKのJVMでの実装は

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

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

src/share/vm/runtime/synchronizer.cpp
     // 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 ;

src/share/vm/runtime/synchronizer.cpp

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

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

src/share/vm/runtime/thread.cpp
  _hashStateX = os::random() ;
  _hashStateY = 842502087 ;
  _hashStateZ = 0x8767 ;    // (int)(3579807591LL & 0xffff) ;
  _hashStateW = 273326509 ;

src/share/vm/runtime/thread.cpp

まとめ

Object.equals()は参照値の比較。
Object.hashCode()の値は各インスタンスでの初回呼び出し時に生成される乱数で、2回目以降の呼び出しは生成済みの乱数を返す。

3
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
4