はじめに
もうタイトルだけで言いたい事は言ってしまった感があります。
私は業務でほとんどJavaしか使ってこなかったので当然のことだと思っていましたが、他の言語を勉強していく内に以外とequals
を使わないことが分かってきました。
Javaの子ども(だと勝手に思っている)Kotlinですら==
で比較できる。
Kotlinでもequals
は使えます。
ということでこの件を浅く掘り下げます。
Stringはプリミティブ型ではない
Stringは1文字目が大文字である事からもわかるようにクラスとなります。
int
やboolean
といったプリミティブ型ではありません。
ではなぜ以下のような宣言ができるのか。
String text = "abc";
int num = 123;
これはStringだけの特殊な仕様により、コンパイラが自動的にStringオブジェクトを生成しているためです。
つまり、String text = "abc";
の宣言は以下と 概念的には 同等になります。
String text = new String("abc");
文字列の比較で==
を使うとどうなるか
クラスは参照型なので==
を使うと同じ参照を見ているかを返します。
しかし下記のコードを実行すると想定と少し異なる結果になります。
String text1 = "abc";
String text2 = "abc";
System.out.println(text1 == text2); // true
System.out.println(text1.equals(text2)); // true
==
で比較した方もtrue
が返ってきました。
これは同じ文字列の値をもつStringオブジェクトが再利用される文字列インターンという特性のためです。
text1
とtext2
は文言が同じため、Stringオブジェクトが再利用され同じ場所を参照します。
そのため==
で比較してもtrue
となるわけです。
ちなみに、Stringクラスのintern()というメソッドが文字列インターンと関連しているよです。
以下のように後から文字列の操作を行うと==
では比較できなくなります。
Stringクラスは不変(イミュータブル)であるため、サンプルのように文字列の結合を行うと、新しいオブジェクトが生成されて、その内容がtext1
とtext2
に設定されるためです。
String text1 = "abc";
String text2 = "abc";
text1 += "def";
text2 += "def";
System.out.println(text1 == text2); // false
System.out.println(text1.equals(text2)); // true
まとめ
Java以外の言語を触った後にJavaを使うと、文字列が一致しているかで==
を使ってしまう人がいるかもしません。
開発環境で正しい設定をしていればそのような場合に警告が表示されると思いますが、Javaで文字列を比較するときはequalsを使うという事を頭の片隅にでも覚えておいてください。