[Java]文字列比較で==はダメ、equalsが正解!・・・なんだけど、その理由をちゃんと知ろう!

java == equals string compare

 

こんにちは。ナガオカ(@boot_kt)です。

 

この問題いつまで消えないんだろ?

 

Javaの文字列比較で==演算子は使っちゃダメ!

equalsメソッドを使え!

 

っていうコレ!

 

そろそろ、この問題をなくしたい!

 

この記事のザックリした内容
◆対象読者

  • Javaの文字列比較で==演算子を使っている人!
  • ==演算子とequalsメソッドの違いが分からない
  • そもそもequalsメソッドなんて知らない

 

◆解決できるかも知れないお悩み

  • ==演算子とequalsメソッドの違いが分かる
  • Stringクラスはポインタって事が分かる!

 

◆どうやって解決するか

  • メモリの中のStringの状態を、図を書いて解説します

 

 

 

プログラマなら絶対に一度は聞いたことあるよね!
Javaの文字列比較に==演算子を使うな!
equalsメソッドを使え!

結論を先に書きますが、

Javaで文字列と文字列が一致しているか否かをチェックする場合、==演算子を使っちゃダメ!
equalsメソッドを使います!!!

え、でも、今まで

if( stringA == stringB )

って書いてちゃんと判断できていたよ

とおっしゃる方もいらっしゃるでしょう

それはたまたまです!
運が良かっただけ!

サンプルを見てみよう!

以下をご覧ください
どういう結果になるか分かりますか?

==演算子を使うパターン

public class Sample1
{
    public static void main(String [] args)
    {
        String hoge = "aiueo";
        String fuga = "aiu".concat("eo");
        
        System.out.println("hoge : " + hoge.toString());
        System.out.println("fuga : " + fuga.toString());
        
        if( hoge == fuga ) {
            System.out.println("[==] 一致");
        } else {
            // ★こっちに入るはず
            System.out.println("[==] 不一致");
        }
    }
}
> java Sample
hoge : aiueo
fuga : aiueo
[==] 不一致

equalsメソッドを使うパターン

public class Sample2
{
    public static void main(String [] args)
    {
        String hoge = "aiueo";
        String fuga = "aiu".concat("eo");
        
        System.out.println("hoge : " + hoge.toString());
        System.out.println("fuga : " + fuga.toString());
        
        if( hoge.equals(fuga) ) {
            // ★こっちに入るはず
            System.out.println("[equals] 一致");
        } else {
            System.out.println("[equals] 不一致");
        }
    }
}
> java Sample2
hoge : aiueo
fuga : aiueo
[equals] 一致

==演算子を使うパターン2

public class Sample3
{
    public static void main(String [] args)
    {
        String fuga = "aiu".concat("eo");
        
        System.out.println("fuga : " + fuga.toString());
        
        if( "aiueo" == fuga ) {
            System.out.println("[==] 一致");
        } else {
            // ★こっちに入るはず
            System.out.println("[==] 不一致");
        }
    }
}
> java Sample3
fuga : aiueo
[==] 不一致

equalsメソッドを使うパターン2

public class Sample4
{
    public static void main(String [] args)
    {
        String fuga = "aiu".concat("eo");
        
        System.out.println("fuga : " + fuga.toString());
        
        if( "aiueo".equals(fuga) ) {
            // ★こっちに入るはず
            System.out.println("[equals] 一致");
        } else {
            System.out.println("[equals] 不一致");
        }
    }
}
> java Sample4
fuga : aiueo
[equals] 一致

結果をまとめると・・・

ね?
文字列比較の場合に==演算子はダメっていうのが分かりますか?

比較方法 結果
==演算子 合致しないと判定された!
equalsメソッド 合致していると判定された!
==演算子 合致しないと判定された!
equalsメソッド 合致していると判定された!

 

理屈

理由を説明します

以下の図を見てください

赤四角:String型の変数
青四角:文字列
黒文字:メモリ上に展開された番地
緑線 :参照の関係性を示しています
java == equals string compare

Stringクラスのインスタンスが生成された時のメモリの状態

赤四角はnewされた時に、メモリ上のどこかに作られます
※図では100番地とか200番地とかって書いていますが、実際にはどこの番地に作られるかは分かりませんし、確認することもできません

青四角の文字列もメモリ上のどこかに作られます
※図では150番地とか280番地とかって書いていますが、実際にはどこの番地に作られるかは分かりません、確認することもできません

メモリ上でのアドレス(番地)について
メモリって、人間世界で言えば土地みたいなものです

「メモリは机の上みたいなもの」と表現されることが多いんですけど、僕は土地に例える方が分かりやすいと考えています

そして、newや変数宣言とは、「空いてる土地を借りられる事」だと説明しています(後で返す必要があるので借りられると表現)

人間世界でも土地を借りたら、もちろん住所がつきます
土地に住所があるのと同じように、メモリにも住所(番地)があります

メモリを「机の上」と表現するのはいいのですが、メモリのアドレス(住所)の事がすっぽり抜け落ちてしまうため、プログラミング時においては良くない表現だと思います
パソコンに増設するメモリを購入するとかっていう場合なら「机の上」がピッタリですけどね
 

で、Javaではこのアドレスを見ることはできません
C言語ではアドレスを見ることはできます

==演算子で比較するということは?

つまり、==演算子で比較するということは、↓こういうことになるとイメージしてください

if (hoge == fuga) {

if (“150番地” == “280番地”) {

“150番地”と”280番地”という住所そのものを比較しているため、それぞれが持つ文字列が同じでも一致しないのです

equalsメソッドで比較するということは?

equalsメソッドであれば、hogeとfugaが参照している先のものを比較します

if( hoge.equals(fuga) ) {

hogeが参照しているのは? → 150番地にある”aiueo”
fugaが参照しているのは? → 180番地にある”aiueo”
ってことで、

if( “aiueo”.equals(“aiueo”) ) {

という感じになります

 

広告




 

さいごに、

この==演算子とequalsメソッドの誤用問題は、いつまでたっても消えませんね
コンピューターの知識をちゃんと持っていれば何ら難しくないんですけど・・・

最近では、

プログラミングという言葉は「単に命令を覚えて、ライブラリの使い方を覚えたらオッケー♪」という意味

と考えている方がいらっしゃるかも知れませんが、きちんとメモリ上での展開が頭に思い浮かべられなければいけません

この記事では、「文字列比較は==演算子じゃなくてequalsメソッドと使いましょう」というそんな単純な一言を言いたいワケではありません

記事中で書いたメモリの図のような内容が頭の中に思い浮かぶよう、理解して欲しいと願っています
 

私がJavaでもC言語でもRubyでもPythonでもプログラミングを教える時はメモリ上の動きを必ず説明します
と言うか、言語はどーーでもいいです
まずはメモリ上の動き、メモリ上のデータの配置ありきです!

メモリに関してはプログラム言語が何であっても同じです

だって、CPUから見たら全てマシン語なんですからね

 


 

プログラミング のレッスンに興味がある方、レッスン内容を聞いてみたい方、なんなりとお問い合わせください。
無料体験レッスンもありますのでお気軽にどうぞ!!!

 

 

参考書籍

 

 

java == equals string compare

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

ABOUTこの記事をかいた人

Windows/Mac/Linuxを使う現役システムエンジニア&プログラマ。オープン系・組み込み系・制御系・Webシステム系と幅広い案件に携わる。C言語やC#やJava等数多くのコンパイラ言語を経験したが、少し飽きてきたので、最近はRubyやPython、WordPressなどのWeb系を修得中。初心者向けのプログラミング教室も運営中。オンライン・対面・出張等でプログラミングをレッスンします。