1
1

More than 5 years have passed since last update.

複数JVMでのClass classのhashCodeについて

Posted at

問題

複数のコンポーネントを持つある分散システムを作っていた時に見つけたこと。
このシステムの各コンポーネントは別々のJVMで動いているが、ある複数のクラスのオブジェクトをserialize, deserializeして共有している。例えばクラスA、クラスB、クラスCがあった時にそれぞれのインスタンスa,b,cをserialize, deserializeするためのserializer, deserializerは下記のようにClassクラスのhashCodeを使って管理していた。簡潔に書くと下記のマップのような管理をしていた。

A.class.hashCode() -> <Serializer for A>
B.class.hashCode() -> <Serializer for B>
C.class.hashCode() -> <Serializer for C>

ところがこのシステムのコンポーネントを部分的に、あるいは全部を再起動するとこのserializer, deserializerが見つからないというエラーが出た。

原因

原因としては自分の想定に間違いがあった。この時に自分はClass自体のhashCodeはどんなときでも変わらないだろうという想定が根拠なくあった。オブジェクトのhashCodeはそのオブジェクトのメンバの値で決められるケースが多いし(もちろんhashCodeの実装による)、この場合クラスAらの実装は何も変更してないからだ。

ところが実際にはクラスA,B,C自体のhashCodeはJVM毎に異なる(可能性もあった)し、同じになるという保証はない。下記のようなコードを動かしてみると確かにクラスAのhashCodeはいつも同じではなかった。

class HashCodeTest {
  public static class A {}
  public static class B {}
  public static class C {}

  public static void printHashCode(Class clazz) {
    System.out.println(clazz + "-> " + clazz.hashCode());
  }

  public static void main(String[] args) {
    printHashCode(HashCodeTest.class);
    printHashCode(A.class);
    printHashCode(B.class);
    printHashCode(C.class);
  }
}
$ java HashCodeTest
class HashCodeTest-> 1829164700
class HashCodeTest$A-> 2018699554
class HashCodeTest$B-> 1311053135
class HashCodeTest$C-> 118352462

順番を変えてみる。

  public static void main(String[] args) {
    printHashCode(A.class);
    printHashCode(HashCodeTest.class);
    printHashCode(C.class);
    printHashCode(B.class);
  }

$ java HashCodeTest
class HashCodeTest$A-> 2018699554
class HashCodeTest-> 1829164700
class HashCodeTest$C-> 1311053135
class HashCodeTest$B-> 118352462

BとCが入れ替わっている。同じクラスでも常に同じhashCodeにはならないようだ。AとHashCodeTestクラスのhashCodeは変わってない。この他に何度か実験してみてロードされるクラスの順番が関係してそうな感じがしたけれど、確かなことはいえない。

でも確かに言えることは異なるJVM上ではたとえ同じクラスでもhashCodeが同じであることは保証されてないということだ。このことはJavaのAPI Referenceを見てもそんなようなことがきちんと書いてあった。

Object#hashCode

Whenever it is invoked on the same object more than once during an execution of a Java application, the hashCode method must consistently return the same integer, provided no information used in equals comparisons on the object is modified. This integer need not remain consistent from one execution of an application to another execution of the same application.

hashCodeのcontractとしてはひとつのJava application起動中でhashCodeが同じになることを保証しているようで、すべての時間と空間を超えたJava application間でのhashCodeに関しては特に言及していなかった。

というわけでJVMまたいだらhashCodeが同じになるとは考えない方がよさそう。いい勉強になった。Class class(Object class?)のhashCodeの実装も見てみたい。

1
1
2

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
1
1