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

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

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

```java:src/share/classes/java/lang/Object.java
    public boolean equals(Object obj) {
        return (this == obj);
    }
```
[src/share/classes/java/lang/Object.java#l149](http://hg.openjdk.java.net/jdk8u/jdk8u/jdk/file/a71d26266469/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](https://docs.oracle.com/javase/specs/jls/se8/html/jls-4.html#jls-4.3.1)

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

```java:share/classes/java/lang/Object.java#l100
public native int hashCode();
```
[share/classes/java/lang/Object.java#l100](http://hg.openjdk.java.net/jdk8u/jdk8u/jdk/file/a71d26266469/src/share/classes/java/lang/Object.java#l100)

下記の記事でとても詳しく説明されています。
[How does the default hashCode() work?](https://srvaroa.github.io/jvm/java/openjdk/biased-locking/2017/01/30/hashCode.html)

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

- OpenJDK 8, OpenJDK 9
    - スレッドごとに持つ値を使って[Xorshift](https://ja.wikipedia.org/wiki/Xorshift)で生成した乱数
- OpenJDK 7, OpenJDK 6
    - [Park & Miller (Lehmer)の乱数発生器](https://en.wikipedia.org/wiki/Lehmer_random_number_generator)([os::random](http://hg.openjdk.java.net/jdk8u/jdk8u/hotspot/file/87ee5ee27509/src/share/vm/runtime/os.cpp#l814))で生成した乱数  
    [線形合同法](https://ja.wikipedia.org/wiki/%E7%B7%9A%E5%BD%A2%E5%90%88%E5%90%8C%E6%B3%95)の一種らしいのですが数学弱すぎてわかりません（＞＜）

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

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

```cpp: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](http://hg.openjdk.java.net/jdk8u/jdk8u/hotspot/file/87ee5ee27509/src/share/vm/runtime/synchronizer.cpp#l580)

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

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

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

[src/share/vm/runtime/thread.cpp](http://hg.openjdk.java.net/jdk8u/jdk8u/hotspot/file/87ee5ee27509/src/share/vm/runtime/thread.cpp#l262)

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