0
0

String型で等値判定(==)と等価判定(equals)を読み解く

Posted at

等値判定と等価判定

sample1
String a = "Hello";
String b = new String("Hello");
if(a == b) System.out.println("TRUE");
else System.out.println("FALSE");

早速ですが、上記のコードを実行すると何が出力されるでしょうか?
答えはFALSEです。

もやもやする方も納得のいく方も、次のコードを見てみてください。

sample2
String a = "Hello";
String b = "Hello";
if(a == b) System.out.println("TRUE");
else System.out.println("FALSE");

では、こちらのコードを実行すると何が出力されるでしょうか?
答えはTRUEです。

上記の2つの例を比べて、何か違和感を感じた方も多いのではないでしょうか。
sample1/sample2ともに、変数aと変数bにHelloを代入しているだけですよね。
なぜ結果が異なるのでしょうか。

等値判定(==)

if文内で使用している演算子(==)は等値であるかどうかの判定、変数そのものの値を比較しているんですね。
なら全てFALSEにならないとおかしいじゃないか、という意見が出てくると思いますし、それはごもっともです。なぜならString型は生成されるたびにメモリ領域のどこかに必要な用量だけ確保されるからです。
つまり、String a = "Hello";を実行した際に、メモリ上のaaaa番地を先頭としてHelloが格納され、変数aにはアドレス番号であるaaaaが格納されるのです。
同様に、String b = "Hello";を実行した際に、メモリ上のbbbb番地を先頭としてHelloが格納され、変数bにはアドレス番号であるbbbbが格納されるのです。
定義するたびに新たに容量が確保され、それらの変数には個別のアドレス番地が格納されるということです。
そして、等値判定では変数そのもの、つまり各変数が保持しているアドレス番地が等しいかどうかを判定するので、当然FALSEでなくちゃおかしいのです。

ですが、文字列リテラルは、コンパイル時にプールと呼ばれる領域に保存されます。同じ内容の文字列リテラルは、プール内にある同じオブジェクトを参照するように最適化されます。
つまり、複数の変数がそれぞれ同じ文字列を持っていても容量の無駄使いとなる(文字列は書き換え不可で、個別に定義する必要がない)ので、コンパイル時には1つだけ生成してあとはみんな同じアドレスを参照しようね、ということになっているのです。
本来なら変数aaaaaが、変数bbbbbが代入されるはずだったのですが、コンパイル時にnnnn番地にHelloが格納され、aもbもnnnnを保持することになるので、等値判定がTRUEとなるのです。

なんでnewで作ったらFALSEになるの

以上の説明から、同じ文字列を定義すると、1つにまとめてみんなそこを参照するようになるんでしたよね。ならなぜsample1の結果はFALSEとなったのでしょうか?
これは単純で、newキーワードを使用すると、毎回新しいオブジェクトが生成されるのですが、オブジェクトは、ヒープと呼ばれる領域に生成されます。
つまり、""で定義した場合とnewで定義した場合では異なるメモリ領域を指すため、==演算子で比較するとfalseになるというだけの話でした。
もちろん、2つともnewで定義しても、それらは別々のヒープ領域を使うので、文字列が同じでも==演算子の結果はFALSEとなります。

等価判定(equals)

では、サンプルコードの判定式を==ではなくequalsで代用するとどうなるか。

sample3
String a = "Hello";
String b = "Hello";
String c = new String("Hello");

System.out.println(a.equals(b)); //true
System.out.println(a.equals(c)); //true

以上のような結果になります。
等価判定とは、対象の変数が指し示す内容が同じかどうかを判定しています。
つまり、変数そのものではなく、変数に入っているアドレスが指し示す先の内容が同じかどうかを見ているわけです。
だから、変数a変数cにはそれぞれ個別のアドレス番地が格納されていますが、どちらの参照先もHelloという内容であるので、equalsの結果はtrueとなるわけですね。

まとめ

今回は等値判定(==)と等価判定(equals)の違いについてまとめてみました。
つまるところ、等値判定の方がより厳しい判定条件ということですね(雑)
ちなみに、equalsはプリミティブ型には使えないので、お気を付けください。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0