#String型比較を深堀してみる
String型の値の比較について、整理しました。
##等比較の方法
###1. ==
・プリミティブ型では値の比較を行う。
・オブジェクト型ではオブジェクトの参照値を比較し、オブジェクトが同一か判断する。
###2. equals()
オブジェクト型でのみ使用可能で、オブジェクトの内容比較を行い、オブジェクトが同値か判断する。
※Objectクラスにequalsが定義されている。
Stringクラスではoverrideしている。
つまり、Strng型は参照型のオブジェクトだから、equalsを使えばOKですね。
##検証(==だと本当に比較できないのか)
String str1 = "A";
String str2 = "A";
String str3 = new String("A");
System.out.println(str1.hashCode());
System.out.println(str2.hashCode());
if(str1 == str2) {
System.out.println("TRUE");
}else {
System.out.println("FALSE");
}
if(str1 == str3) {
System.out.println("TRUE");
}else {
System.out.println("FALSE");
}
##結果
100
100
TRUE
TRUEになった。String型は==でも比較していいのか。
#調査
String型は初期化された際にヒープ領域に値が作られるが、同じ値を使用する場合は使いまわすらしい。
※newされた場合は新しく領域が作られる。
メモリ節約のため、newせずに値"A"が一致する領域(アドレス=100)を使いまわす。
※参照値:参照先のメモリアドレス
変数の値を書き換えると参照元の値(アドレス=100)が変更されるのではなく、"B"の新しい領域をnewして参照先を変更するんですね。(参照先アドレスを100→200に変更)
※Stringはイミュータブルのため、参照先の値を変更できない。
#Stringオブジェクトのequalsはなにをやっているか
private final char value[];
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = value.length;
if (n == anotherString.value.length) {
char v1[] = value; //自オブジェクトのvalue
char v2[] = anotherString.value; //比較先オブジェクトのvalue
int i = 0;
while (n-- != 0) {
if (v1[i] != v2[i]) //Stirngをcharに分解して値比較
return false;
i++;
}
return true;
}
}
return false;
}
Stringオブジェクトをchar[]に分解して1つずつ値を比較している。
#結論
Stringオブジェクトはメモリ節約のために同じ値の場合は異なるローカル変数でも参照値(参照先アドレス)が同一になる可能性があるが、保証はされていないので、equalsで比較するべし。