Javaのequalsメソッドを完全解説!初心者向けの同値性の基本
生徒
「Javaでオブジェクトが同じ値を持っているかどうかを確認したいんですが、どうすればいいですか?」
先生
「それにはequalsメソッドを使いますよ。同値性を判断する方法を詳しく解説していきますね。」
生徒
「equalsメソッドの基本的な使い方が知りたいです!」
先生
「OK、それでは基本から実践まで一緒に学んでいきましょう!」
1. equalsメソッドとは?
Javaのequalsメソッドは、2つのオブジェクトが同じ値を持っているかを確認するためのメソッドです。デフォルトでは、Objectクラスに定義されていますが、そのままでは参照を比較するだけの実装になっています。
デフォルトのequalsメソッド
public boolean equals(Object obj) {
return (this == obj);
}
デフォルトでは、参照が同じかどうかを確認します。値の比較をしたい場合は、equalsメソッドをオーバーライドする必要があります。
2. サンプルコードで学ぶequalsメソッドの使い方
以下のサンプルコードでは、numフィールドが一致すれば同値とみなすようにequalsメソッドをオーバーライドしています。
public class Sample {
private int num;
private String name;
public Sample(int num, String name) {
this.num = num;
this.name = name;
}
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (obj instanceof Sample) {
Sample s = (Sample) obj;
return s.num == this.num;
}
return false;
}
}
このクラスを使うと、次のような結果が得られます:
public class Main {
public static void main(String[] args) {
Sample obj1 = new Sample(10, "Alice");
Sample obj2 = new Sample(10, "Bob");
System.out.println(obj1.equals(obj2)); // true: numが一致しているため
}
}
このコードでは、numが一致しているため、equalsメソッドはtrueを返します。
3. equalsメソッドの実装ポイント
- nullチェック:比較対象が
nullの場合はfalseを返します。 - 型の確認:
instanceofを使って、正しい型かどうかを確認します。 - フィールドの比較:比較したいフィールドが一致しているかを確認します。
これらのポイントを抑えることで、正確なequalsメソッドを実装できます。
4. equalsメソッドのカスタマイズ
以下のコードでは、複数のフィールドを使った比較を行っています:
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null || getClass() != obj.getClass()) {
return false;
}
Sample sample = (Sample) obj;
return num == sample.num && Objects.equals(name, sample.name);
}
この実装では、numとnameの両方が一致している場合にtrueを返します。
5. equalsメソッドの注意点
- 必ずhashCodeメソッドもオーバーライドする:同じ値を持つオブジェクトは同じ
hashCodeを持つべきです。 - 比較するフィールドを明確にする:すべてのフィールドを比較する必要はありません。
- テストを行う:複数のケースで
equalsメソッドが正しく動作するか確認します。
6. 同一性と同値性の違いを正しく理解する
Javaには「同じ」を表す考え方が2種類あります。それは、演算子 == を使う「同一性」と、equalsメソッドを使う「同値性」です。
プログラミング未経験の方にも分かりやすく例えると、同一性は「世界に一つだけのその物自体が同じか」を指し、同値性は「見た目や内容(スペック)が同じか」を指します。
以下のコードで、その決定的な違いを確認してみましょう:
public class CompareExample {
public static void main(String[] args) {
String str1 = new String("Java");
String str2 = new String("Java");
// 同一性の比較(別々のオブジェクトなのでfalse)
System.out.println(str1 == str2);
// 同値性の比較(文字列の内容が同じなのでtrue)
System.out.println(str1.equals(str2));
}
}
実行結果は以下のようになります:
false
true
このように、newを使って新しく作られたオブジェクトは、中身が同じでも「別物」としてメモリに保存されるため、内容で比較したいときは必ず equals を使う必要があります。
7. Objects.equalsを使った安全な比較方法
equalsメソッドを自分で呼び出す際、最も怖いのが「比較元が null だった場合にプログラムが停止してしまう(NullPointerException)」ことです。
Java 7から導入された java.util.Objects.equals を使うと、変数が null であっても安全に比較を行うことができます。
import java.util.Objects;
public class SafeCompare {
public static void main(String[] args) {
String a = null;
String b = "Java";
// a.equals(b) だとエラーになるが、Objects.equalsなら安全!
System.out.println(Objects.equals(a, b));
}
}
実行結果:
false
実務の現場では、予期せぬエラーを防ぐためにこの Objects.equals を活用するのが一般的です。初心者の方も、この「安全な書き方」をセットで覚えておくと、バグの少ない綺麗なコードが書けるようになります。
8. equalsメソッドを自作する練習課題
理解を深めるために、実際に簡単なクラスを作って equals メソッドを実装してみましょう。今回は「商品(Item)」クラスを作成し、商品名が同じであれば同じ商品だと判定するプログラムです。
class Item {
String name;
Item(String name) {
this.name = name;
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (!(obj instanceof Item)) return false;
Item other = (Item) obj;
// 名前が同じならtrueを返す
return this.name.equals(other.name);
}
}
public class Practice {
public static void main(String[] args) {
Item item1 = new Item("りんご");
Item item2 = new Item("りんご");
System.out.println("比較結果: " + item1.equals(item2));
}
}
実行結果:
比較結果: true
このように、自分で「どのデータが同じなら、このオブジェクトは同じだと言えるのか」を定義するのが equals のオーバーライドの本質です。この基礎をマスターすれば、複雑なデータの管理もスムーズに行えるようになります。
まとめ
今回の記事では、Javaのequalsメソッドについて解説しました。equalsメソッドは、オブジェクトの同値性を判断するための重要なメソッドです。デフォルトの実装は参照の比較しか行いませんが、クラスごとに適切にオーバーライドすることで、オブジェクトの値の比較が可能になります。
具体的な実装では、nullチェック、instanceofによる型の確認、比較対象のフィールドの明確化が重要です。また、equalsメソッドをオーバーライドする際には、必ずhashCodeメソッドもオーバーライドする必要があります。これにより、HashSetやHashMapといったコレクションでの動作を保証できます。
サンプルコード
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null || getClass() != obj.getClass()) {
return false;
}
Sample sample = (Sample) obj;
return num == sample.num && Objects.equals(name, sample.name);
}
@Override
public int hashCode() {
return Objects.hash(num, name);
}
このコードでは、numとnameの両方を比較対象とし、hashCodeメソッドもオーバーライドしています。これにより、コレクションやアルゴリズムにおける一貫性が保たれます。
生徒
「equalsメソッドのオーバーライドがこんなに重要だとは知りませんでした!具体的にどのような場面で使うんですか?」
先生
「例えば、同じ値を持つオブジェクトをHashSetに格納するとき、equalsとhashCodeが正しく実装されていないと、意図しない結果になる可能性があります。」
生徒
「なるほど!つまり、正しい実装をすることでコレクションや検索アルゴリズムが正確に動作するんですね。」
先生
「その通りです。同値性を正しく扱うことは、Javaプログラムの信頼性を高める重要なポイントです。」