プログラミング言語や環境設定を中心としたパソコン関連の技術メモです。
主にシステム開発中に調べたことをメモしています。TIPS的な位置付けで、気が向いたときにちまちま更新していきます。
Java、==とequals()の違い
「『==』と『equals()』って、何がどう違うのですか?」と某会社の新人さんに質問されたので、
自分の復習と次回以降の説明の手間を省くためにメモっておきます。

一言で大雑把に言ってしまうとですね。

「==」は「同じ物ですか?」の比較、「equals()」は「同じ値ですか?」の比較で使います。

とは言え、実はこれ、キッチリ見ると結構ややこしいのですよね(-A-)
微妙にいろいろ予備知識が必要なので、補足しておかないと混乱を招きそうです。

それではまず最初の予備知識(--)b

Javaにはオブジェクトではない型が存在します。

「プリミティブ型(基本型)」と呼ばれる奴等でboolean、char、byte、short、int、
long、float、doubleがありますよ。

こいつらはオブジェクトではありません。
それぞれラッパークラスが用意されているので、オブジェクトとして扱いたいときは

int ival = 1;
Integer i01 = new Intger(ival);



Integer i01 = new Intger(1);

のようにすればオブジェクト化できますけどね。

おや?
プリミティブ型には文字列を入れる型がありませんね?
文字を入れる「char」はありますが文字『列』を入れる型がありません。
地味に大事なので覚えておいてください。


次に2つ目の予備知識(--)b

String型には「擬似プリミティブ型」と呼ばれる書き方があります。
本来の決まりでは

String s01 = new String("hoge");

と書くべきなのですが

String s01 = "hoge";

のように書くこともできるのです。
「よく使うし、いちいちnewとか書くの面倒でしょ?」とJavaさんが配慮してくれている訳ですね。
まぁ、これが初心者にとっては罠なんだけどさ(-。-)ぼそっ


最後に3つ目の予備知識(--)b

Java5だかそこら辺から「Autoboxing」なるものが実装されました。
これは、本来

Integer i01 = new Intger(1);

と書くべきところを

Integer i01 = 1;

と書いてもいーよ、な内容です。
Javaさんの方で「おいらがnewして代入してやるよ~」と配慮してくれている訳ですね。
まぁ、これも罠なんだけどさ(-。-)ぼそっ

前振りが長くなりましたが、いよいよ本題です。
まずは基本的なところからいきましょうかね。

プリミティブ型との比較は「==」でも「equals」でもどちらでも良いです。

例えば

Integer i01 = new Integer(1);

System.out.println("■i01 == 1");
if(i01 == 1){
    System.out.println("同じだよ");
}else{
    System.out.println("違うよ");
}

System.out.println("■i01.equals(1)");
if(i01.equals(1)){
    System.out.println("同じだよ");
}else{
    System.out.println("違うよ");
}

の実行結果は

■i01 == 1
同じだよ
■i01.equals(1)
同じだよ

になります。
「==」も「equals()」も同じ結果ですね。

オブジェクト同士の比較では「同じオブジェクトを参照しているか」を調べるときは「==」で
「同じ値か」を調べるときは「equals()」を使う必要があります。

例えば

Integer i03 = new Integer(1);
Integer i04 = new Integer(1);
Integer i05 = i04;

System.out.println("■i03 == i04");
if(i03 == i04){
    System.out.println("同じだよ");
}else{
    System.out.println("違うよ");
}

System.out.println("■i03.equals(i04)");
if(i03.equals(i04)){
    System.out.println("同じだよ");
}else{
    System.out.println("違うよ");
}

System.out.println("■i04 == i05");
if(i04 == i05){
    System.out.println("同じだよ");
}else{
    System.out.println("違うよ");
}

System.out.println("■i04.equals(i05)");
if(i04.equals(i05)){
    System.out.println("同じだよ");
}else{
    System.out.println("違うよ");
}

を実行すると、結果は

■i03 == i04
違うよ
■i03.equals(i04)
同じだよ
■i04 == i05
同じだよ
■i04.equals(i05)
同じだよ

になります。
i03とi04は中に入っている値は同じですが、別々にnewしているのでオブジェクト自体は別です。
そのため「==」での比較は「違うよ」になります。別のオブジェクトだから。
値が一緒なので「equals()」の比較は「同じだよ」ですけどね。

i05はi04を代入(i04のオブジェクトへの参照を代入)しているので、
i04もi05も見ているオブジェクトは同じです。
そのため「==」での比較が「同じだよ」になります。
もちろん値も一緒なので「equals()」の比較も「同じだよ」です。

ここで最初の予備知識を思い出してください。

文字列用のプリミティブ型は存在しませんでした。
つまり文字列の比較はオブジェクト同士の比較になるのです。

これが、文字列の比較では「equals()」を使いなさい、とよく言われる理由です。

Javaに慣れていないうちは、ついつい

String s01 = new String("hoge");
if(s01 == "hoge"){
    System.out.println("同じだよ");
}else{
    System.out.println("違うよ");
}

と書きたくなってしまいますが、これは間違いです。
この書き方は実質

String s01 = new String("hoge");
String s02 = new String("hoge");
if(s01 == s02){
    System.out.println("同じだよ");
}else{
    System.out.println("違うよ");
}

と同じですからね。
「s01 == "hoge"」の部分が「参照しているオブジェクトが同じですか~?」の比較になり、
参照しているオブジェクト自体は別なので結果は「違うよ」になります。

ここまでが基本編(--)b

ここからは応用編と言うか、バグりやすいところの補足です。

2つ目の予備知識でString型は

String s01 = "hoge";

のような書き方ができると言いました。
実はこの書き方をした場合、Javaさんがメモリの節約を試みます(-A-)
出来る限り既存の資源を利用しようと頑張るっぽくてですね。

String s05 = "hoge";
String s06 = "hoge";


System.out.println("■s05 == s06");
if(s05 == s06){
    System.out.println("同じだよ");
}else{
    System.out.println("違うよ");
}

System.out.println("■s05.equals(s06)");
if(s05.equals(s06)){
    System.out.println("同じだよ");
}else{
    System.out.println("違うよ");
}

の結果が

■s05 == s06
同じだよ
■s05.equals(s06)
同じだよ

になります。
s05とs06で同じオブジェクトを参照しているようです。

宣言を

String s01 = new String("hoge");

形式から

String s05 = "hoge";

形式に変えただけで「==」の比較結果が変わってしまいましたね。
紛らわしい。

そろそろお腹いっぱいですか?
「もうちっとだけ続くんじゃ」です。

3つ目の予備知識で「Autoboxing」なるものが実装されたから

Integer i01 = new Intger(1);

と書くべきところを

Integer i01 = 1;

と書いてもいーよ、と言いました。
これが罠です(-A-)

こいつもJavaさんが「出来る限り」メモリを節約しようとして、
同じオブジェクトを参照しようと頑張ります。
ですから

Integer i06 = 127;
Integer i07 = 127;

System.out.println("■i06 == i07");
if(i06 == i07){
    System.out.println("同じだよ");
}else{
    System.out.println("違うよ");
}

System.out.println("■i06.equals(i07)");
if(i06.equals(i07)){
    System.out.println("同じだよ");
}else{
    System.out.println("違うよ");
}

の実行結果は

■i06 == i07
同じだよ
■i06.equals(i07)
同じだよ

となります。
「i06」と「i07」が同じオブジェクトを参照していますね。

ただし(--)b

Integer i08 = 128;
Integer i09 = 128;

System.out.println("■i08 == i09");
if(i08 == i09){
    System.out.println("同じだよ");
}else{
    System.out.println("違うよ");
}

System.out.println("■i08.equals(i09)");
if(i08.equals(i09)){
    System.out.println("同じだよ");
}else{
    System.out.println("違うよ");
}

の実行結果は

■i08 == i09
違うよ
■i08.equals(i09)
同じだよ

になります。
おや?「i08」と「i09」は違うオブジェクトを参照しているようです。
代入する値を127から128に変えただけなんですけどね(--ゞ

これは内部的に-128から127までのIntegerをキャッシュしているかららしいです。
-128から127の範囲であれば既に準備してあるのを見に行くけど、
それ以外であれば新しくオブジェクトを作るってことですね。

もう何が何だか分かんねーよ(T_T)な方、ご安心ください。
私も書いていて微妙な気分になってきました。

細かい部分はあまり意識しないで

1.プリミティブ型との比較は「==」でOK
 ※「equals()」でも比較できるので、心配だったら「equals()」を使えばOK

2.オブジェクトの値の比較は「equals()」を使う

3.オブジェクト自体の比較は「==」を使う
 ※同じオブジェクトを参照しているかの比較

と覚えておけば良いと思います。

まぁ基本的にはオブジェクトそのものよりは値を比較する機会の方が多いでしょうからね。
心配だったら「equals()」を使っておけば良いんじゃないですか?(適当)

長くなったけど、そんな感じ(--)ノ
スポンサーリンク
 
このエントリーをはてなブックマークに追加 

category:● Java  thema:システム開発 - genre:コンピュータ  Posted by ササキマコト 

  関連記事