久しぶりに

最近、久しぶりにStringを==で比較してうまく動かず
悩んでる人を見かけたので、おそらくホワイトボードでの
説明回数は2桁に到達するであろうこの話題について触れてみる


まず


int a = 10;
int b = 10;


if(a == b) {
System.out.println("同じ");
}


このプログラムで
同じ
と出力される理由は
変数aのために確保したメモリに
書き込まれてる値(この場合は10)
と変数bのために確保したメモリに書き込まれている
値が同じかを判断するからである。


Javaにおいてプリミティブ型は変数用に確保したメモリに
直接値を書き込むので単純にこの比較で問題ない
しかし、参照型の場合は事情がちょっと違ってくる


今回はString型を扱っているので忘れがちだが通常参照型の場合
Object object = new Object();
のようにnewを使ってインスタンスを生成する
これはどういうことかというと、
まず、newした際にメモリ上のどこかにインスタンス用の
メモリ領域を確保する
次に、コンストラクタを呼び出したりとかの最初に行う処理が実行される
その後で、確保したメモリ領域のアドレスをreturnしている
その結果、今回の変数objectには帰ってきたアドレスが格納される


ここがプリミティブ型と決定的に違うところである
・プリミティブ型
値が直接変数に格納される
・参照型
値(インスタンス)がある場所が変数に格納される


ではここでなぜStringが==で比較できないかである
なんとなくもうおわかりの方もいるかもしれないが


//str1用に"string"を格納するメモリが確保される
String str1 = "string";
//str2用に"string"を格納するメモリが確保される
String str2 = "string";


//str1とstr2の値が一緒かを調べる
//この際str1, str2の値はそれぞれがインスタンス
//場所を示している
if(str1 == str2) {
System.out.println("同じ");
}


こんな感じである。
要するに本来比較したい値が同じでもnewするたびにそれぞれ別な領域が確保されるため参照先が違うものになってしまう
その結果、変数自体に入っている値は別なものになるので
if文を通らない


さて、ではどのように比較すればいいか
Objectクラスにあるequals()メソッドを利用する
このメソッドはインスタンスが同じかを判断するために利用するメソッド
で各クラスごとにオーバーライドして利用される
Stringでは文字列が一緒かを比較するように実装されているため


if(str1.equals(str2))


とすることで本来やりたい処理を行える


というわけである
以上