Javaのプログラムでは、さまざまな場面で「equals」を使います。しかし、「equals」は使い方を間違えると、正しくない返し値や出力をすることとなり、エラーや間違ったコード構造を生み出しかねません。
それを防ぐには、「equals」の使い方をしっかりとマスターすることです。本記事では、「equals」のメソッドや比較演算子を中心に特徴の違いや使い方を解説します。
目次
1.Java equalsとは
「equals」は、Javaで使われるメソッドです。主に、「equals()」メソッドやStringクラスで使う比較演算子を指します。
「equals」の意味や定義
Javaの「equals」は、比較した値が同じか判定することができます。元々「equals」は、英語「equal」の複数形で「等しい」「同等」を意味します。その意味を当てており、「equals」には比較する値が同じであることをチェックする機能があるのです。
例えば、演算子「==」を使った「A == B」は、AとBを比べて同じものなら「true」、違うなら「false」を返すという機能です。「equals()」メソッドにも、同一値の比較(同じ値か比べる)で結果を返す機能があります。
ちなみに、演算子とは「算術演算子(「+」「-」)」や「代入演算子」(「=」「+=」)など計算の種類を示す記号のことです。「equals」で「==」のことを正式には「比較演算子」と呼びます。
「=」ではなく「==」を使う理由
「equals」では、「==」の演算子を使用します。一般的に、「等しい」で思い浮かべる演算記号は「=」(イコール)ですが、プログラミングの世界では「=」は等式以外にも使用場面があるため、「=」だけでは同一比較ができません。例えば、「=」は値の定義や変数の更新に使われます。
これらの理由から、Javaでは比較対象を指定する際に「=」を使いません。「==」の演算子や「equals()」を使って比較します。
2.Java equals()メソッドと==で比較することの違い
「equals」と「==」は、基本的にどちらも「比較して「true」か「false」を返す」という点で同じです。しかし、「equals」と「==」では、Javaにおいて比較する内容や方法に違いがあります。
「equals」の型は2種類
「equals」の型には、以下の2つの種類があります。
プリミティブ型
オブジェクト型
「プリミティブ型」とは、メソッドがない値(文字列や数値、論理値など)の「型」に該当します。一方、「オブジェクト型」は、Javaのオブジェクトクラスでインスタンスを生成する型です。
型によって比較基準が違う
ここで気をつけるべきは、「equals()」メソッドと「==」では比較基準が異なることです。具体的には、プリミティブ型の場合は「左右の「値」が等しい」か、オブジェクト型では「オブジェクトのが同じもの」かを比較します。
型を重視したオブジェクト指向のJava特有の違いで、プログラミング学習者の方が混同しやすい部分です。
比較基準が違う原因は変数
「equals()」メソッドと「==」で比較基準が違う理由は、変数の違いにあります。プリミティブ型には、変数に「値」が入っています。それに対して、オブジェクト型には、変数に「インスタンスの参照先(メモリアドレス)」が格納されているのです。
つまり、オブジェクト型を演算子の「==」で比較すると、「変数(インスタンスの参照先含む)」が同じか比較します。「equals()」メソッドは内容が同じなら「true」を返しますが、「==」では内容の値が同じでも参照先が異なれば「false」を返します。
「同値性」と「同一性」の違い
「equals()」メソッドでは、インスタンスの参照先が別でも内容の「値」が同じなら「true」を返します。この値とは、オブジェクトの持つデータのことです。この値が同じことを「同値性」と呼びます。インスタンスが同じで、値が違う場合に結果は「false」となります。
逆に、比較演算子「==」はインスタンスの参照先が同じなら「true」で、インスタンスが別の参照先の場合には同じ値でも正しく判定できず「false」を返します。これが「同一性」と呼ばれるものです。日付などは「同一性」でエラーの出る代表格で、数値が同じでも「false」です。
以上、「equals()」メソッドと比較演算子「==」は、比べるときの「性質」が異なるのです。
3.Java equalsの基本的な使い方は?
「equals」の基本的な使い方についてソースコードの例を使って説明します。
数字の同値判定
「equals」の使い方として、まずはデータ型のintで整数を比べて判定する方法があります。例えば、数字の「3」と「2+1」が同じか知りたいときは、「equals」の比較演算子「==」で調べます。
public class Main { public static void main(String[] args) { int x = 3; int y = 2 + 1;
// equals メソッドの正しい使用例 // プリミティブ型をラッパークラスに変換して equals を使用 Integer objX = Integer.valueOf(x); Integer objY = Integer.valueOf(y); System.out.println(objX.equals(objY)); // true
// 文字列の比較 - equals の一般的な使用例 String str1 = "Hello"; String str2 = "Hello"; String str3 = new String("Hello");
// 文字列の内容比較には equals を使用する(正しい) System.out.println(str1.equals(str2)); // true System.out.println(str1.equals(str3)); // true
// 文字列に == を使うと参照比較になる(注意が必要) System.out.println(str1 == str2); // true(String Pool のため) System.out.println(str1 == str3); // false(異なるオブジェクト) } } |
上記の例では、intで定義して変数を使った比較です。一方、下記の例では「==」で値を直接比較しています。
public class Main { public static void main(String[] args) { System.out.println(3 == (2 + 1)); } } |
「2+1」と「3」は答えが同じですから、実行するとどちらも「true」が出力されます。ただし、この方法は、Javaの基本型となるプリミティブ型で値を直接格納している場合のみ正しく「true」と出力される方法です。
ちなみに、整数以外のプリミティブ型で「char」や「double」は、同じ数字を「==」で比較すると「true」を正しく出力できます。そのため、プリミティブ型なら正しく返す仕組みです。
整数比較の例外:ラッパークラス
同じ整数でもラッパークラスは例外です。「Integer」は、同じ整数でも「false」が出るなど、正しく出力されません。これは、intの変数をラップしてオブジェクトにしているためです。プリミティブ型しか扱えない比較演算子「==」では間違った答えが返される理由となっています。
また、「char」や「double」をラッパークラスにした「Double」「Character」でも間違った判定をする点は同じです。そのため、正しい判定にはオブジェクト型の「equals()」メソッドを使用します。
変数が「オブジェクト型」の数値比較
オブジェクト型を「==」で正しく判定することはできません。そこで、変数にオブジェクトを扱える「equals()」メソッドを使います。ソースコードを作成する際に、「equals()」メソッドは初期化して呼び出すオブジェクトの指定が必要です。
public class Main { public static void main(String[] args) { Integer x = 3; Integer y = 2 + 1;
} } |
上の例のように「equals()」メソッドを使った場合は、正しく「true」と出力されます。しかし、「x y」のようにプリミティブ型の比較演算子「」を使うと「false」が出て失敗となるのです。
Javaのequalsで文字列を比較する
Javaでは、文字列を比べる際に比較演算子「==」を使わず、「equals()」メソッドを使用します。これはJavaにおいて文字列の変数がオブジェクトとして扱われるからです。
public class Main { public static void main(String[] args) { String x = "これは例です"; String y = "これは"+"例です"; String z = new String("これは例です");
System.out.println(x.equals(z)); System.out.println(z.equals(y));
} |
上記の出力では、いずれも「true」が表示されます。格納場所として、xとyは「プール領域(不変のメモリ)」、zは「ヒープ領域(オブジェクト用のメモリ)」が参照先です。ちなみに、比較演算子「==」を使うと、エラーは発生しませんが、参照の比較となるため、同じ内容でも異なるオブジェクトの場合は正しく判定できません。
関連記事
Javaとは?Web開発で利用されるJavaの特徴や実行方法、おすすめ資格を解説
4.equalsの応用的な使い方
上記では、equalsの基本的な使い方を確認しましたが、ここでは応用的な使い方を紹介します。
Javaの「equals」を否定する方法
「equals」では比べるものが「同じ」か調べる方法です。しかし、その条件を反対にして「同じでない」ことを「equals」で調べることができます。それが否定演算子「!」です。具体的には、比べるオブジェクトの前に「!」を入れます。
public class Main { public static void main(String[] args) { Integer x = 3; Integer y = 2+1;
} } |
xとyは3で同じ値を持つので、本来は「true」です。しかし、 上の例では、それを否定する「!」の演算子を入れているため、「xが同じではない(等しくない)」場合に「true」、同じ場合に「false」と判定が逆に変わります。
ただし、この方法はシンプルで簡単ですが、オブジェクト型をStringクラスで書いた場合は、「null」が入ったときにエラー「NullPointerException」が発生します。そのため、次の2つの方法のいずれかで「null」の実行を回避します。
パターン1.「areNotEqual()」メソッドを使い「null」のチェックを途中で入れる
パターン2.内部機構で「null」の確認ができるメソッドを使う
途中で「null」チェックの例は以下です。
import java.util.Objects; public class Main { public static void main(String[] args) { Integer x = 3; Integer y = 2 + 1;
System.out.println("片方または両方がnullです"); } else { System.out.println(!Objects.equals(x, y)); } } } |
次は、「areNotEqual()」メソッド呼び出し前に途中で「null」チェックの例です。
public class Main { public static void main(String[] args) { Integer x = 3; Integer y = 2 + 1;
}
if (x == null) { return y != null; } return !x.equals(y); } } |
「Integer x」のみを「null」チェックしている理由は、「areNotEqual()」メソッド内では、null 安全な比較を行うために、まず x が null かどうかをチェックしています。
これは、null オブジェクトに対して equals メソッドを呼び出すと NullPointerException が発生するのを防ぐためです。。
このメソッドでは、x が null の場合と null でない場合で異なる処理パスを実行します。x が null の場合は y も null かどうかで結果を決定し、x が null でない場合は通常の equals 比較の否定を返します。
実行が止まるわけではなく、条件によって異なる結果を返すだけです。
また、「null」のチェックが組み込まれている「Objects」クラスの「Objects.equals(,)」メソッドを使うのが効率的です。以下はそのソースコード例です。
import java.util.Objects;
public static void main(String[] args) { Integer x = 3; Integer y = 2 + 1;
} } |
この例では、実行内部に「null」チェックの機能がすでに備わっているため、別途「null」チェックする必要がありません。
Javaの「equals」で複数を比較する方法
「equals」で複数を比較するには、「areAllEqual() 」メソッドでデータを並べます。その際に、ifとfor構文からオブジェクトの判定を行います。以下は、すべて一致するか判定する数字の複数比較の例です。
import java.util.Objects;
public static void main(String[] args) { System.out.println(areAllEqual(1, 2, 3, 4)); System.out.println(areAllEqual(1, 1, 1, 1)); }
if (values.length < 2) return true;
for (int i = 1; i < values.length; i++) { if (!Objects.equals(first, values[i])) { return false; } } return true; } } |
Javaの「equals」で複数条件を提示する方法
今度は「equals」で複数条件を出す方法です。簡単な方法では、Stringやintに値を入れて「1,2,3,4」をそれぞれintの変数で定義し、「System.out.println(Objects.equals(,);」を複数書くなどして出力する方法です。
ただし、この方法は設定する値の個数が縦に多いと「System.out.println」で出力する数が増大して、コード記述が大変なため、別の方法でまとめるなどします。
例えば、「boolean型(真偽値型)」で複数条件に合致するものを1つずつforやifで設定し「return true;」「return false;」で返す方法があります。このときに気をつけることは、「equals()」メソッドだけにこだわらず、自然なメソッドを選択して記述することです。
下記の例では、「null」チェックにのみ「Object.equals()」メソッドを使い、そこに自然数(正の整数)の条件、すべて奇数の条件を複数並べています。条件のどれか1つでも「false」が返ると、その値の比較は「false」となります。
public class Main { public static void main(String[] args) { System.out.println(areAllEqual(1, 2, 3, 4)); System.out.println(areAllEqual(1, 1, 1, 1)); System.out.println(areAllOdd(1, 3, 5, 7)); System.out.println(areAllOdd(1, 2, 3, 4)); }
if (objects.length <= 1) { return true; // 0または1つの要素は「すべて等しい」と見なす } Object first = objects[0]; for (int i = 1; i < objects.length; i++) { // nullの安全な比較のためにObjects.equalsを使用 if (!java.util.Objects.equals(first, objects[i])) { return false; } } return true; }
public static boolean areAllValid(Object... objects) { for (Object obj : objects) { if (!isValid(obj)) { return false; } } return true; }
if (obj instanceof Integer) { return (Integer) obj >= 1; } return true; // 整数でない場合は常に有効と見なす }
for (Object obj : objects) { if (obj instanceof Integer) { if ((Integer) obj % 2 == 0) { return false; } } } return true; } } |
上記は複数の値(整数)を比べていますが、boolean型の「compareValues」を使い、文字列と数字の一致や値の大きさの条件(ifにこれを加えて trueを返す複数条件)を追加する方法もあります。
Javaの「equals()」メソッドで「null」を比較する方法
「equals()」メソッドには、「null」を入れて比べる方法もあります。まず、前提として「null」はプリミティブ型で格納できず、オブジェクト型に入れる必要があります。
つまり、変数にオブジェクトの参照値格納を前提としていることから、比較演算子「==」ではなく「equals()」メソッドを使います。
その上で、「String str = null;」のようにStringクラスで変数に「null」を代入し、「Objects.equals(,)」のメソッドで同値を比較します。
import java.util.Objects;
public static void main(String[] args) { String str1 = null; String str2 = "3";
}
return Objects.equals(str1, str2); } } |
「null」の使用そのものを避けたい場合は、「null」の代わりに空(「""」)などを初期値に入れます。上記の例では「false」が出力され、空(「""」)の場合も同様の結果が得られるのです。
5.Java equalsを使用するときのポイントや注意点
「equals」のメソッドや比較演算子を使用する場合には、以下のような注意点があります。
問題の起こりにくい実装をする
まず1つ目は、業務の実装で「equals」を使う場合に、問題の起こりにくいソースコードで組むことです。エラーやバグは、作業工程を鈍らせるだけでなく、大規模な開発では「null」のエラーを始めとしてさまざまな問題が後で見つかることがあります。
特に、「equals」を使って実務で複雑なデータ比較を成功させるには、比較条件やその基準(性質)を正しく理解して実装することが大事です。すでに述べたように、「equals」だけにこだわらず、さまざまなメソッドを適材適所で使うことも問題を回避する方法の1つです。
独自比較は自分で基準を作る
2つ目は、内容の何を比較するかは作成者が決定することです。プログラムには、テキストデータなどを自身の価値判断(種類の比較、色の比較など)で自動的に比較基準を変えることはできません。
例えば、犬と猫はカテゴリ上では動物で同じです。しかし、データの「同値性」としては異なります。そのため、「同一性」により参照先が同じかや、カテゴリのメソッド(Locale.Category)、コレクション(Collectionクラス)などで柔軟にソースコードを作成します。
「equals()」メソッドはサブクラスでオーバーライドする
Javaでは、クラスを継承することができます。その際に「オーバーライド」と呼ばれるクラスのメソッドと同じ名称のサブクラスを再定義することが可能です。この場合、親子の関係となり、親となるのが「スーパークラス」、子となるのが「サブクラス」です。
そして、「equals()」メソッドは、サブクラスにオーバーライドします。特に、「equals()」と「hashCode()」の深い関係性が背景にあります。
例えば、「equals()」の値が同じなら「hashCode()」(ハッシュ値)も同じです。そのため、サブクラスに「equals()」メソッドを継承する際は、どちらもオーバーライドすることが必要です。
両者をオーバーライドすることで、正しい論理値を返す「論理等価」が期待できます。例えば、リストのCollectionクラスを使う際、この方法では値の格納や検索などで一貫性を保てるのです。
関連記事
Javaのオーバーライド攻略|オーバーロードとの違いや使い方・条件・戻り値などわかりやすく解説
6.「equals」に関するよくある質問
ここでは、「equals」のメソッドや実装などでよくある質問に回答します。
「equals()」メソッドは「equals(object)」のこと?
「equals()」メソッドの基本は「equals(object)」です。しかし、「equals()」のメソッドにはStringクラスとObjectクラスがあり、変数がオブジェクトの場合だけではありません。
また、「equals()」メソッドの()の中は「object.equals(object)」のように単独な場合と、「null」チェックのできる「equals(object,object)」で区切っている場合があります。
オブジェクト比較を正確にするコツは?
オブジェクト比較を正確にするには、「equals()」メソッドの比較が「同値性」なことを理解し、比較演算子との使い分けや否定、複数の条件付け、オーバーライドなどのルールを守ることです。
特にJavaは比較演算子とメソッドで異なる結果を返します。また、Javaに多い「null」が入るような曖昧な記述の仕方ではバグやエラーを抱える問題もあるでしょう。
そのため、「object.equals()」のメソッドを基本として、途中の「null」チェックやその確認を省略できるメソッドを使うなど対策を施します。
「equals」でSystemクラスやif構文をよく使う理由は?
「equals」では、コードが同じか調べるため、それを出力するか、条件分岐の起点(フラグ管理)とすることが多いためです。Systemクラスの基本出力やifで「false」を返すなら実行を止める、といったフラグ管理として基本的な使い方ができるなど、利点が多いのも理由です。特に、
7.まとめ
今回は、Javaの「equals」の定義や使い方のポイントなどを解説しました。「equals」には「equals()」メソッドと比較演算子「==」があり、「同値性」(値が同じ)と「同一性」(インスタンスの参照先が同じ)を比べて「true」や「false」を返すことができます。
応用的な使い方では、否定や複数比較、複数条件などがあり、場合に応じて使い分けが可能です。「equals」で効率的な作成を目指す方は、オブジェクトの比較で「null」チェックを備える「object.equals(,)」メソッドを使うのがおすすめです。
本記事が皆様にとって少しでもお役に立てますと幸いです。