0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

JavaSilverを学習して初めてStringについて深堀してみた。

Posted at

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
  • == は参照(メモリ上のアドレス)を比較する演算子であり、
    ab は別のオブジェクトを参照しているため、false になるはずだと考えていた。

しかし結果はtrueだった。
なぜこのようなことが起きるのかを調査してみた。


結論

結論を先に述べると、JavaではJVM起動時やクラスロード時に
String Constant Pool(文字列定数プール) に文字列リテラルが格納され、
同じ文字列リテラルを使用している変数は、その参照を使いまわす。

そのため、上記のコードでは ab が同じ参照を指し、
a == btrue になる。

本記事では、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つだけ保持される
  • Stringimmutable (不変)であり、安全に共有できる。

要するに、
クラス内に出てきた文字列リテラルを、重複しないように管理する大きな箱
のような存在になります。


String Constant Pool では何が行われているのか

クラスがロードされる際、
クラス内に文字列リテラルが存在すると、 JVM は以下の処理を行います。

  • クラスに 文字列リテラル が出てきたら、
  • JVMString オブジェクトを用意する。

つまり、

"sample"という文字列がコード上に出てきた時点で、
"sample"のStringオブジェクトが、
String Constant Pool に用意される


なぜ a == btrue になるのか

改めて、最初のコードを見てみる。

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 という変数に代入している。
      つまり、
  • ab
  • 同じ String Constant Pool 内の "sample" を参照している。
    そのため、
System.out.println(a == b);

true になる。


おわりに

今回は、String Constant Pool の挙動と
なぜ a == btrue になるのかについて記述してみました。
このような仕様は、
単に言語を「書ける」だけでなく、
内部の挙動として理解しておく必要があると感じた。
まだ駆け出しのPGですが、様々な学習を通して
疑問に思った点を深堀する記事を書いていきたいと思います。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?