==と文字列プール

このレッスンでできるようになることは、文字列の ==equals の結果を、文字列プールの仕組みから説明できるようになることです。

まず予測してみます

次の 3 つの出力を決めてください。

String a = "java"; String b = "java"; String c = new String("java"); System.out.println(a == b); System.out.println(a == c); System.out.println(a.equals(c));

答えは順に true、false、true です。Java Silver で最も出題数が多い論点のひとつです。

文字列プール

ソースに直接書いた "java" のような文字列リテラルは、文字列プールという共有の置き場に 1 つだけ作られます。同じ内容のリテラルが何度出てきても、同じインスタンスが使い回されます。だから a == b は true です。

== は参照型に使うと「同じインスタンスか」を見ます。中身が同じかどうかは見ません。new String("java") は必ず新しいインスタンスを作るので、プールの中の "java" とは別物です。よって a == c は false になります。中身の比較をしたいときは equals を使います。

連結がいつプールに入るか

ここが引っ掛けの本命です。

String x = "ja" + "va"; // true になる String y = "ja"; String z = y + "va"; // false になる final String w = "ja"; String v = w + "va"; // true になる

リテラルどうしの連結はコンパイル時に 1 つの定数へまとめられるので、プールの "java" と同じインスタンスになります。final を付けた w も定数変数として扱われるので同じです。ところが final の無い変数 y を使った連結は実行時に組み立てられるため、新しいインスタンスになります。final が 1 つ付いているかどうかで答えが反転する、という形で出題されます。

intern

intern() は「この内容でプールに登録されているインスタンス」を返します。実行時に作った文字列でも、intern() を通せばリテラルと == で一致します。

System.out.println(z.intern() == x); // true

ただし実務では equals を使えば済むので、intern() を書く場面はほとんどありません。試験用の知識と割り切ってください。

演習

実行時に組み立てた文字列を == で比べているせいで、いつも不一致になるメソッドがあります。直してください。

要件

  1. same は語の内容が java と等しいかどうかを表すこと
  2. pooled は語をプールに寄せたうえで、リテラルの java と同一インスタンスかどうかを表すこと
  3. 戻り値は same と pooled を半角コロンでつないだ文字列にすること

入出力例

match("ja", "va")"true:true" match("ja", "x")"false:false" match("j", "ava")"true:true" match("java", "")"true:true"

ヒント

生田 陸人
ゆめさくエンジニア / 現役ソフトウェアエンジニア
編集 LuaGate編集部
main.java
学習モード

メモ

==と文字列プール

⌘S で保存