Java Silver学習で学んだString Constant Poolの挙動
普段何気なくJavaを書いていたが、自分のJavaについての知見はどの程度あるのだろうか?と思い、Java Silverの学習を始めてみた。
学習を進める中で、序盤に以下のコードに出会った。
String a = "sample";
String b = "sample";
System.out.println(a == b); // true
私はこの設問は false になると思っていた。
なぜ false になると思ったのか
理由は以下の通りである。
- Javaの
Stringは仕様的にはオブジェクトであり、プリミティブではない - 普段、現場で文字列を比較する際は、値を比較するために
equals()を使用している
System.out.println(a.equals(b)); // true
-
==は参照(メモリ上のアドレス)を比較する演算子であり、
aとbは別のオブジェクトを参照しているため、falseになるはずだと考えていた。
しかし結果はtrueだった。
なぜこのようなことが起きるのかを調査してみた。
結論
結論を先に述べると、JavaではJVM起動時やクラスロード時に
String Constant Pool(文字列定数プール) に文字列リテラルが格納され、
同じ文字列リテラルを使用している変数は、その参照を使いまわす。
そのため、上記のコードでは a と b が同じ参照を指し、
a == b が true になる。
本記事では、String Constant Poolの挙動と
なぜこの比較結果が true になるのか に焦点を当てて説明する。
(String Constatnt Poolがなぜ存在するのかについては、次回の記事で扱う予定)
new を使用していないのにStringを宣言できるのはなぜか
まず、私は 文字列 について深堀をしていく中で、次のコードを見て少し不思議に思った。
String a = "sample";
Javaにおいて、String はクラスであるはずにもかかわらず、
なぜ new 演算子を使わずに宣言できるのだろうか。
実際、以下のような書き方も可能である。
String a = new String("sample");
クラスの宣言しているのだから、こちらの書き方の方がより理にかなっていると私は感じます。
なぜこのように、new を使用しても使用しなくてもかけてしまうかというと、
Javaでは、Stringはクラスであるにもかかわらず、
文字列リテラルを使用した場合は特別な扱いを受ける。
これは、言語仕様としての特例である。
この特例を理解するために、 String Constant Pool について説明します。
String Constant Pool とは何か
String Constant Pool とは、以下のような特徴を持ちます。
-
JVMが管理する文字列専用の共有領域 - 文字列リテラル(
"sample"など)を格納する - 同じ文字列は1つだけ保持される
-
Stringはimmutable(不変)であり、安全に共有できる。
要するに、
クラス内に出てきた文字列リテラルを、重複しないように管理する大きな箱
のような存在になります。
String Constant Pool では何が行われているのか
クラスがロードされる際、
クラス内に文字列リテラルが存在すると、 JVM は以下の処理を行います。
- クラスに
文字列リテラルが出てきたら、 -
JVMがStringオブジェクトを用意する。
つまり、
"sample"という文字列がコード上に出てきた時点で、
"sample"のStringオブジェクトが、
String Constant Poolに用意される
なぜ a == b が true になるのか
改めて、最初のコードを見てみる。
String a = "sample";
String b = "sample";
このとき起きていることは以下の通り。
-
String a = "sample";-
String Constant Pool内にある"sample"の参照をaという変数に代入している。
(String Constant Pool内のオブジェクトは、クラスロード時に作成されるため、実行時には既に、存在している。)
-
-
String b = "sample";-
String Constant Pool内にある"sample"の参照をbという変数に代入している。
つまり、
-
-
aもbも - 同じ
String Constant Pool内の"sample"を参照している。
そのため、
System.out.println(a == b);
は true になる。
おわりに
今回は、String Constant Pool の挙動と
なぜ a == b が true になるのかについて記述してみました。
このような仕様は、
単に言語を「書ける」だけでなく、
内部の挙動として理解しておく必要があると感じた。
まだ駆け出しのPGですが、様々な学習を通して
疑問に思った点を深堀する記事を書いていきたいと思います。