オブジェクト同士をequalsで比較する前にJavaTips 〜Javaプログラミング編

» 2007年02月20日 10時00分 公開
[平野正喜@IT]

 クラス階層のルートであるjava.lang.Objectクラスは、すべてのクラスのスーパークラスであり、メソッドを実装するすべてのオブジェクトは、このクラスのメソッドを自動的に実装します。

 このObjectクラスにあるequals(Object)メソッドは、あるオブジェクトとほかのオブジェクトが等しいかどうかを示します。そこで、Javaが提供しているクラスの一部では、equals(Object)メソッドをオーバライドすることで、「このクラスにとっては、あるオブジェクトとほかのオブジェクトが等しいとは、こういう場合である」と定義しています。

 例えば、java.lang.Stringクラスは、equals(Object)メソッドをオーバライドして「この文字列と指定されたオブジェクトを比較し、引数がnullでなく、このオブジェクトと同じ文字列を持つStringオブジェクトである場合にtrueを返す」と再定義しています。

 しかし、java.lang.Stringクラスに似ているjava.lang.StringBufferクラスでは、再定義を行っていません

 ですから、下の図1のプログラムと実行例を見てのとおり、同じ文字列を持つStringオブジェクト同士のequals(Object)はtrueになり、同じ文字列を持つStringBufferオブジェクト同士のequals(Object)はfalseになります。

図1 StringとStringBufferでは、同じ文字列を持つオブジェクトどうしのequals(Object) 図1 StringクラスとStringBufferクラスのequals(Object)メソッドの挙動の違いを示すプログラム

 ということで、equals(Object)メソッドを用いる場合は、それがオーバライドされているかどうかを確認する必要があります。

 一例として、java.langパッケージに含まれている主なクラスでは、以下のように分類されます。

  • equals(Object)メソッドをオーバライドしているクラス

    BooleanByteCharacterDoubleFloatIntegerLongShortString

  • equals(Object)メソッドをオーバライドしていないクラス

    ClassProcessRuntimeStringBufferThreadThreadGroup

自前のクラスでequals()メソッドをオーバライドするには

 自前のクラスにおいて、「このクラスにとっては、あるオブジェクトとほかのオブジェクトが等しいとは、こういう場合である」と定義したい場合、equals(Object)メソッドをオーバライドすると良いでしょう。

 ただし、同時にhashCodeメソッドをオーバライドして、「等価なオブジェクトは等価なハッシュコードを保持する必要がある」という hashCodeメソッドの汎用規約に従うことが求められます。そのクラスが使い捨てではなく、ほかのクラスから用いられる場合は、必ず留意しましょう。

 一例として、2つの文字列を保持するMyTwinStringクラスを考えます。MyTwinStringクラスでは、あるオブジェクトとほかのオブジェクトで、保持する2つの文字列が両方ともに等しい場合に「等しい」とします。ハッシュコードを2つの文字列を用いて生成すると、以下のようになります。

図2 2つの文字列を保持するMyTwinStringクラス 図2 2つの文字列を保持するMyTwinStringクラス

 この例では、2つの文字列のハッシュコードの和をそのオブジェクトのハッシュコードとしています。これで「等価なオブジェクトは等価なハッシュコードを保持する必要がある」という hashCodeメソッドの汎用規約が実現します。

 ただし、この方法では「MyTwinString("A", "B")」と「MyTwinString("B", "A")」のハッシュコードが等しくなりますので、このクラスの使い方によっては、hashCode()メソッドの内容を工夫すべきでしょう。

Profile

RunDog.org

平野正喜


Copyright © ITmedia, Inc. All Rights Reserved.

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。