equalsとは?
Javaのequalsとは、あるオブジェクトと別のオブジェクトの「中身」が同じかどうかを調べるためのメソッドです。Javaの全てのクラスの親であるObjectクラスに定義されているため、どのオブジェクトでも利用できます。
Javaには比較の手段として==演算子もありますが、これは2つの参照が同じオブジェクトを指しているかどうかを判定するものです。一方、equalsメソッドは「値」や「内容」が等しいかどうかを判定します。
例えば、2つの文字列変数にそれぞれ同じ文字を代入した場合、==演算子では生成方法によってtrueにもfalseにもなり得ますが、equalsメソッドを使えば文字の内容が同じであれば確実にtrueを返します。この違いを理解していないと、バグの原因になります。
Stringクラスをはじめ、IntegerやListなど多くの標準クラスではequalsメソッドが適切にオーバーライドされており、中身の比較ができるようになっています。自分で作成したクラスでも、equalsメソッドをオーバーライドすることで、オブジェクト同士をどのような条件で「等しい」と判断するかなど、独自のロジックを定義できます。
基本構文
equalsメソッドの基本的な書き方はとてもシンプルです。比較元のオブジェクトからequalsを呼び出し、引数に比較先のオブジェクトを渡します。戻り値はboolean型で、内容が等しければtrue、異なればfalseを返します。
equalsメソッドは文字列だけでなく、多くのオブジェクト同士の比較に使用できます。まずは、文字列を使った基本的な比較の例を見ていきましょう。
出力結果
true変数aと変数bはどちらも「ネコ」という同じ文字列を持っているため、equalsメソッドはtrueを返します。
次に、異なる文字列を比較した場合の例です。
出力結果
false「ネコ」と「イヌ」は異なる内容であるため、falseが返されます。
もう一つ、数値のラッパークラスであるIntegerで比較する例を見てみましょう。
出力結果
trueInteger型はオブジェクトであり、一部の値はキャッシュされ再利用されます。 扱う数字によって挙動が変わるわけです。このため、==演算子を用いると、扱う値によって、結果が変わる可能性があります。例えば「127までは true だったのに、128になった途端に false になる」という、見つけにくいバグにつながる場合もあるため、注意が欠かせません。
equalsメソッドを使えば、内部の数値が同じかどうかを判定できます。オブジェクトの内容を比較する場合は、==演算子ではなくequalsメソッドを使用するのが基本です。一方で、同じオブジェクトを参照しているかどうかを確認したい場合は、==演算子を使用します。
実用例
ここからは、Javaのequalsメソッドの実践的な使い方をコード例とともに紹介します。文字列の比較だけでなく、==演算子との違いの確認、大文字・小文字を無視した比較、nullに対する安全な比較、独自クラスでのオーバーライド、Objects.equalsの活用、そしてリスト内の要素検索といった、開発の現場でよく使われる場面を取り上げます。
それぞれのコード例では、まずそのコードで何をしているかの概要を説明し、コードの後に動作の詳細を解説しています。初めてequalsメソッドに触れる方でも、順番に読み進めることで理解しやすい構成です。
なお、コード例では変数名などに動物の名前を使用しています。身近な名前を使うことで、処理の流れを直感的に追いやすくなります。各コードは短く簡潔にまとめているので、手元の開発環境にコピーして実際に動かしてみてください。
文字列同士をequalsで比較する
2つの文字列変数に格納された動物名が一致するかどうかを、equalsメソッドで確認します。文字列比較の最も基本的なパターンです。
出力結果
true
falseanimal1とanimal2はどちらも「キツネ」という同じ文字列であるため、equalsの結果はtrueになります。一方、animal1とanimal3は「キツネ」と「タヌキ」で内容が異なるため、falseが返されます。
Javaで文字列を比較する場合は、==演算子ではなくequalsメソッドを使うのが原則です。==演算子はオブジェクトの参照先を比較するため、同じ文字列であっても生成方法によってfalseになることがあります。equalsメソッドを使えば、純粋に文字の内容だけを比較できます。
==演算子とequalsの違いを確認する
new演算子で生成した2つの文字列を、==演算子とequalsメソッドの両方で比較し、結果の違いを確認します。
出力結果
false
true==演算子での比較結果はfalseになります。これは、new String()で生成するとヒープ領域にそれぞれ別のオブジェクトが作られ、cat1とcat2が異なるメモリアドレスを指すためです。一方、equalsメソッドは文字列の内容を比較します。cat1とcat2はどちらも「ネコ」という同じ内容の文字列であるため、trueを返します。
この違いはJava初学者がつまずきやすいポイントの一つです。文字列やラッパークラスなどオブジェクトの内容を比較する場合は、equalsメソッドを使用するのが基本です。
大文字・小文字を無視して比較する
英語表記の動物名を、大文字・小文字の違いを気にせず比較します。equalsIgnoreCaseメソッドを使うことで、ケースを無視した比較ができます。
出力結果
false
true通常のequalsメソッドは大文字と小文字を区別するため、「Penguin」と「penguin」は異なると判定されfalseが返ります。しかしequalsIgnoreCaseメソッドを使えば、アルファベットの大文字・小文字の違いを無視して内容を比較できます。
ユーザーからの入力を受け付ける場面では、入力値の大文字・小文字が統一されていないことが少なくありません。そのような場合にequalsIgnoreCaseを使うと、大文字・小文字の違いを意識せずに比較できます。
なお、このメソッドはStringクラスに固有のものであり、Object.equalsとは別に用意されています。
nullを安全に扱って比較する
比較元の変数がnullになる可能性がある場面で、NullPointerException(null参照によって発生する例外)を回避しながら安全にequals比較を行う方法を示します。
出力結果
falseもしanimal.equals("ウサギ")と書いた場合、animalがnullであるためNullPointerExceptionが発生してプログラムが異常終了します。これを避けるためのテクニックが、リテラル側からequalsを呼び出す書き方です。
「ウサギ」という文字列リテラルは確実にnullではないため、引数にnullが渡されてもメソッドは正常に動作し、falseを返します。この書き方は「nullセーフなequals比較」と呼ばれ、実務でもよく使われるパターンです。
変数の値がnullになり得る場面では、リテラルや確実にnullでないオブジェクトを比較元にすることで、安全なコードを書けます。
独自クラスでequalsをオーバーライドする
自作のクラスで、名前フィールドの値が同じであれば等しいと判定するように、equalsメソッドをオーバーライドします。
出力結果
trueObjectクラスのデフォルトのequalsメソッドは、==演算子と同じく参照の一致を判定します。そのため、自作クラスでは中身が同じでも、異なるインスタンスであれば falseになってしまいます。
上記のコードは、equalsメソッドをオーバーライドし、引数がAnimal型であればnameフィールドの値を比較する例です。これにより、異なるインスタンスであっても名前が同じならtrueを返すようになります。
なお、equalsをオーバーライドする場合はhashCodeメソッドも合わせてオーバーライドするのが原則です。HashMapやHashSetなどのコレクションで正しく動作させるために必要となります。
equalsとObjects.equalsを使い分ける
java.util.Objects.equalsを使うと、どちらかの引数がnullであっても例外を発生させずに比較ができます。null同士の比較にも対応しています。
出力結果
true
falseObjects.equalsは、Java 7で導入された静的メソッドです。このメソッドは、まず両方の引数が同じ参照かどうかを確認し、次に片方がnullでないことを確認した上でequalsメソッドを呼び出します。そのため、どちらかまたは両方がnullであってもNullPointerExceptionが発生しません。
上記の例では、aもbもnullであるためObjects.equalsはtrueを返します。2行目はnullと「クマ」の比較なのでfalseになります。リテラルを先に書くテクニックと比べて、どちらの変数がnullになるかを意識する必要がないため、可読性が高く安全なコードを書くことができます。
リスト内の要素をequalsで検索する
ArrayListに格納された動物名の中から、特定の文字列と一致する要素があるかをcontains(要素を含むか判定する )メソッドで確認します。containsメソッドは内部でequalsを使って要素を比較しています。
出力結果
true
falseListのcontainsメソッドやindexOf(要素位置を取得 )メソッドは、リスト内の各要素に対してequalsメソッドを順番に呼び出し、一致するものがあるかを調べます。
上記の例では、「ゾウ」はリストに含まれているためtrueが返り、「キリン」は含まれていないためfalseになります。このように、equalsメソッドはプログラマーが直接呼び出す場面だけでなく、Javaの標準ライブラリの内部でも数多く使われています。独自クラスのオブジェクトをリストに入れて検索したい場合は、そのクラスにequalsメソッドを正しくオーバーライドしておく必要があります。
まとめ
Javaのequalsメソッドは、オブジェクトの内容が等しいかどうかを判定するための仕組みです。==演算子が参照先の一致を確認するのに対し、equalsメソッドはオブジェクトの内容を比較するという違いがあります。文字列比較や数値のラッパークラスの比較など、日常的なコーディングの幅広い場面で活用されます。
また、equalsメソッドはStringやIntegerなどの標準クラスで既にオーバーライドされていますが、自作のクラスではデフォルトで参照比較となるため、必要に応じて自分でオーバーライドする必要があります。その際はhashCodeメソッドも合わせてオーバーライドすることが求められます。
nullが混在する可能性がある場面では、リテラル側からequalsを呼び出すテクニックやObjects.equalsメソッドを活用することで、NullPointerExceptionを未然に防ぐことができます。
equalsの活躍する場面
- ユーザー入力値と期待する文字列の一致確認
- コレクション内の要素検索やフィルタリング処理
- 独自オブジェクト同士の論理的な等価判定
重要なポイント
- ==演算子は参照比較、equalsは内容比較という違いの理解
- equalsをオーバーライドする場合はhashCodeも実装する
- Objects.equalsやリテラル側からの呼び出しでnullを安全に扱う
Javaのequalsメソッドは、Javaプログラミングにおいて避けて通れない基本的な機能の一つです。==演算子との違いを正しく理解し、null安全な書き方やオーバーライドの作法を身に付けておくことでバグを防ぎ、信頼性の高いコードを書くことができます。まずは本記事で紹介したコード例を実際に動かしてみて、equalsメソッドの挙動を体感するところから始めてみてください。