こんにちは! ピョコです!
エンジニアである私自身が資格勉強(特にJavaSilver)で悩んだところを簡単に分かりやすく説明する2回目。
今回のテーマは「==」と「equals」
皆さんはこの違い分かりますか?
この2つの区別をしっかり理解しているでしょうか?
できてるよという方は復習がてら、まだだよという方は是非読んでみてください!
この記事を読んでほしい人
■ 「==」と「equals」についてあまり理解ができていない人
■ Javaの資格勉強でつまづく人
ではさっそく学んでいきましょう。
「==」とは
「==」とはプリミティブ型を比較する場合、2つの値が等しいかを比較するために使用されます。
例えば
int i = 1;
int j = 1;
System.out.println(i == j);
この場合、画面にはtrueと表示されます。
当たり前ですよね、同じ値なのですから。
では参照型の場合は?という疑問が浮かぶと思います。
参照型の場合は参照先が同じかどうかを比較します。
「?」って思う方には参照型の説明下の1回目で詳しく解説しております。
例えばSampleクラスというクラスがあるとします。
Sample sample1 = new Sample();
Sample sample2 = new Sample();
Sample sample3 = sample1;
①System.out.println(sample1 == sample2);
②System.out.println(sample1 == sample3 );
①の場合はfalseと表示され②の場合はtrueと表示されます。なぜでしょう。これはnewされた時のイメージを掴むとわかりやすくなると思います。
newされた場合、新しい参照先にインスタンスが生成されます。今回の場合はsample1とsample2をnewして新しく生成されるので別々の参照先にインスタンスが生成されます。
「==」は参照先が同じかどうかを比較するので、
①の場合はfalseが表示されます。
では②の場合はどうでしょう。
②のsample3ではnewで新しくインスタンスを生成しているわけではありません。sample1が参照している参照先をsample3も参照しているのです。
「==」は参照先が同じかどうかを比較するので、
②の場合はtrueが表示されます。
では①の場合比較して同じものだとしたい場合どうすればいいのでしょう。
そんな時に使うのが「equals」です。
次に「equals」の説明に入りたいと思います。
equalsとは
「equals」とは参照型を比較するために使います。よく言う言葉では「equals」は同値性を確認するものです。
参照型のものを比較する場合にはこのequalsを使います。
同値性の比較なので同じ値であればこのequalsメソッドはtrueを返します。
と思ってる方。それは間違いです。equalsメソッドは同じ値ならtrueをすべて返すわけではありません。
ではequalsメソッドがtrueを返すものは何なのか。
それはこのequalsメソッドのオーバーライドでtrueを返すものだけなのです。逆に言えばオーバーライドを行っていてもtrueを返さない処理を組んだり、オーバーライドをしないで使ったりするとfalseが返ってくることもあります。
public class Sample {
public int sampleInt;
public String sampleString;
public boolean equals(Object obj) {
if(obj instanceof Sample) {
Sample sample = (Sample) obj;
return sample.sampleString.equals(this.sampleString);
}
return false;
}
}
例えばこの場合だとsampleStringが同じであればtrueが返ってきます。
public class Sample {
public int sampleInt;
public String sampleString;
public boolean equals(Object obj) {
if(obj instanceof Sample) {
Sample sample = (Sample) obj;
return sample.sampleInt == this.sampleInt;
}
return false;
}
}
この場合だとsampleIntが同じであればtrueが返ってきます。
このようにequalsメソッドの中で比較しているものが同じであればtrueを返します。
え、でもオーバーライドをしないで使ったことあるよ??
ってかStringで使ったし…という人。
それはString型では既存の状態でオーバーライドをしているからです。
なのでオーバーライドをしなくても使用することができます。
このように参照型は「==」ではなく「equals」を使用することで比較を行います。なぜなら「==」は参照型の場合、参照先が同じかどうかでしか判断できないからです。値が同じかどうかで判断したい場合は「equals」です。
難しいという方は参照型は「equals」をプリミティブ型は「==」で比較すると覚えてもらっても構わないです。
ただ「equals」は絶対にオーバーライドをして使いましょう。
コンスタントプール
さて先ほどは参照型は「equals」で比較するという話をしました。
ではString型を比較するときは
String greeting1 = "こんにちは";
String greeting2 = "こんにちは";
System.out.println(greeting1.equals(greeting2));
このように行います(trueと表示)
では「==」を使った場合どうなるのでしょうか?
String greeting1 = "こんにちは";
String greeting2 = "こんにちは";
System.out.println(greeting1 == greeting2);
さてどうなるのでしょうか。
falseと表示されると思った方、しっかり勉強ができています。
ですがここではtrueと表示されます。
なぜでしょうか。
実はコンスタントプールというものがあります。
String型やInteger型などの参照型では同じ値を変数に代入する場合、コンスタントプールと呼ばれる場所を見に行きます。そこで同じ値のものがある場合、その値の参照先を参照するようになっています。なので上記の場合「==」でも比較ができるようになっています。
えー、何そのパターン…って感じですよね。
正直これに関しては現場で使うことはほとんどないと思います。というよりequalsメソッドがあるのにわざわざ「==」で比較する必要がありません。
ただ試験ではこの部分が出たりするので頭の片隅に入れておいてもらえばと思います。
無理という方は覚えなくてもいいと思います。
その場合は参照型は「equals」でプリミティブ型は「==」と覚えておいて、理由も押さえておきましょう。
余談
String型の「equals」はオーバーライドをすでにしてあるという話をしていたのを覚えているでしょうか。
実は「equals」はObjectで定義されているのです。なのでStringは「equals」をオーバーライドしているというような説明になっているのです。(クラス階層のルート)
ではなぜオーバーライドしなければいけないのでしょう。
Objectクラスのequalsメソッドの処理は以下のようになっています。
public boolean equals(Object obj) {
return (this == obj);
}
これを見てもらえれば分かるのですが、自分自身と渡されたインスタンスの参照先が同じかどうかで判定を返します。
ですのでこれをオーバーライドしないで使うと参照先が同じかどうかでしか判定しません。
同じ値かどうかで判定したい場合はオーバーライドするしかないですね。
まとめ
私はequalsをオーバーライドする理由がよくわからず、どうやってオーバーライドするのか苦戦をしていました。
ですがオーバーライドをする理由が分かれば何を比較の対象にするのかが分かりオーバーライドもかなりしやすくなりました。
なぜを深く考えることができれば覚えなくても自然とコードをかけるようになります。
ただ覚えるだけではなく、なぜを突き詰めてしっかり理解して「==」と「equals」を使ってみてください!
もちろん資格の取得にも活かしてみてください!