はじめに
Eclipseを使用して実装している。hashCode()とかequals(Object)を生成してくるのだが、hashCode()はいいのだが、equals(Object)は長くて見にくい。いや、ちゃんと動くし、いいんですよ。しかし、個人的には生成されたソースが見た目悪いので、どうやればすっきりとしたソースになるか検証してみた。
基本のソース
public class EqualsTest {
private String name;
private int age;
private boolean isMan;
}
ベースのクラスはこんな感じ。オブジェクト、数値リテラル、boolean型を網羅するようにした。
hashCode()を見る
Eclipseが生成するコードは下記のよう。良いと思う。
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + age;
result = prime * result + (isMan ? 1231 : 1237);
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
equals(Object)を生成する
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
EqualsTest other = (EqualsTest) obj;
if (age != other.age)
return false;
if (isMan != other.isMan)
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
オブジェクト部分が長いと思う。一つのオブジェクトに5行だと、10つオブジェクト変数があると、50行になる。それは頂けないかと。
自分でequals(Object)を考えてみる
public boolean myEquals(Object obj){
if (this == obj) return true;
if (obj == null || hashCode() != obj.hashCode() || ! (obj instanceof EqualsTest)) return false;
EqualsTest other = (EqualsTest) obj;
boolean result = true;
result = result && (isMan == other.isMan);
result = result && (age == other.age);
result = result && (name == null ? other.name == null : name.equals(other.name));
return result;
}
こんな感じでどうだろう。
変数がオブジェクトでも一行。だいぶ行数の節約になるはず。
生成されたソースはfalseとわかった時点でreturnしているので実行速度は速い。それに対し、こちらは変数分の判定を実施しているので遅い。しかし、個人的にはそのデメリット以上に見やすくて良いつもり。
getClassとinstanceOfの違い
さて二つの相違点として型比較を、生成されたものはgetClass()で、自分で考えてみたものはinstanceOfを使用しています。どこで差が出てくるかというと、継承を使ったときです。「Effective Java 第2版」の項目8から引用させて頂きます。
単純な座標情報のクラスPointがあったとします。Pointに色情報を追加したサブクラスColoredPointを作ります。さて、PointとColoredPointで座標が同じ場合どうなるでしょうか。
point.equals(coloredPoint)ではPointには色情報がないのだから、座標情報があればequalsはtrueでは?でもcoloredPoint.equals(point)は色情報の有無があるからfalseになるべきでは、ということになります。本来point.equals(coloredPoint)とcoloredPoint.equals(point)の結果は同じにならなければならないのに。
ちなみに本書のなかでは「継承よりコンポジションを選びなさい」というオチになってます。継承せずに、PointとColorの変数を持つColoredPointを作ろう、と。
終わりに
ソースは、
https://github.com/xaatw0/quiita/blob/master/src/EqualsTest.java
に置いてあります。生成されたequalsと自分で作成したequalsが同じ結果を出すことを確認したテストコード、継承を使ったときは違う結果になるテストコードも入っています。
それにしても、普通equalsの実装で皆さんどうされているのでしょうか。