Javaのjava.lang.Stringのintern()の説明で出てくるPool of Stringsって何ぞ?

 

f:id:ts0818:20201222180006j:plain

gigazine.net

1968年~1974年にかけて、アメリカ・カリフォルニア州で少なくとも5人が殺害された未解決事件「ゾディアック事件」で、犯人が残した暗号文である「340暗号文」が51年越しに解読されたと報じられています。

謎の連続殺人事件「ゾディアック事件」の暗号文が51年間越しに解読される、その全容とは? - GIGAZINE

⇧ 51年越しって...

オランチャク氏らによる暗号解読を受けて、FBIはサンフランシスコ・クロニクルを通じて「FBIはゾディアック事件の暗号が民間人によって解読されたことを認識しています。当該事件は、地元の法執行機関との協力により現在も捜査が進められています」との声明を発表しました。

謎の連続殺人事件「ゾディアック事件」の暗号文が51年間越しに解読される、その全容とは? - GIGAZINE

⇧ 捜査が継続されてるってのも驚きだけど、暗号が解読されても手掛かりになるような情報にならなかったところが辛いところですね。

そんなこんなで、今回もJavaについてです。

レッツトライ~。

 

Javaの型とメモリ領域

Javaの全てのオブジェクトは、JVM(HotSpot VMに限定?になるのかな)側のOOP(Ordinary Object Pointer)って仕組みで管理されてるっていうことが分かったわけなんですが、

ts0818.hatenablog.com

 

Javaって「静的型付け」な言語ということで、「型」についてきっちりしているということなんですが、大きく分けて、 

  • プリミティブ型 ※1
  • 参照型 ※2

※1:boolean型、byte型、char型、long型、short型、int型、float型、double型

※2:Boolean型、Byte型、Character型、Long型、Short型、Integer型、Float型、Double型といったラッパークラス、Decimal型、String型、Object型などなど

に分かれると思うんだけど、JVMJava Virtual Machine)ってのは、「.java」ファイルがJDKJava Developmet Kit)なんかに同梱されてる「javac」のようなコンパイラーで「.class」ファイルが生成されてから、初めて処理を進めることができると思われるわけなんだけど(JVMの概要図とか見ると「Class Loader」が起点になってるので)、

⇧ 「.class」ファイルの内容は、上図で言うと「JVM Memory」のいずれかに配置されていくのだと思うのですが、「プリミティブ型」と「参照型」って配置される場所ってどうなるんだっけ?

 ってことで、

blog.jamesdbloom.com

This article explains the internal architecture of the Java Virtual Machine (JVM). The following diagram show the key internal components of a typical JVM that conforms to The Java Virtual Machine Specification Java SE 7 Edition.

https://blog.jamesdbloom.com/JVMInternals.html

⇧ 上記サイト様がJVMの内部について解説してくれています。

Java SE 7」時点の内容ということで、「Java SE 8」で「PermGen(Permanent Generation for VM metadata)」とか無くなって、JVMのMemory構成が変わってるあたりとかの影響とかが分からないのですが、参考になるかと。

で、説明を読んでいくと、

  • プリミティブ型
    • Stack
      • Frame
        Local Variables Array
  • 参照型
    • Stack
      • Frame
        Current Class Constant Pool Reference
        • Class Data
          Run-Time Constant Pool
    • Heap

って感じで、「プリミティブ型」「参照型」で配置されるJVMのMemory領域が異なりますと。「参照型」については、インスタンス化してオブジェクトになったら「ヒープ」領域に配置されるんだと思われます。

 

Pool of Stringsって?

で、ようやっと本題。

String型ってのは、Javaの場合「参照型」に分類されると思うんだけど、ちょっと特殊な管理をされてるっぽいんですよ。 

どういうことかと言うと、 

docs.oracle.com

public final class String
extends Object
implements Serializable, Comparable<String>, CharSequence

Stringクラスは文字列を表します。Javaプログラム内の"abc"などのリテラル文字列はすべて、このクラスのインスタンスとして実行されます。

https://docs.oracle.com/javase/jp/8/docs/api/java/lang/String.html

⇧ まず、第一に、「リテラル」でインスタンス化できるという。

普通だと「new演算子」でコンストラクタでインスタンス化するってのが一般的だと思われますが、String型は、

String str = "abc";
String str = new String("abc");
char data[] = {'a', 'b', 'c'};
String str = new String(data);

⇧ ってな感じで、「new演算子」を使わなくても、使っても、どちらでもインスタンス化できますと。

で、本題の「Pool of Strings」ですが、

public String intern()

文字列オブジェクトの正準表現を返します。

文字列のプールは、初期状態では空で、クラスStringによってプライベートに保持されます。

internメソッドが呼び出されたときに、equals(Object)メソッドによってこのStringオブジェクトに等しいと判定される文字列がプールにすでにあった場合は、プール内の該当する文字列が返されます。そうでない場合は、このStringオブジェクトがプールに追加され、このStringオブジェクトへの参照が返されます。

https://docs.oracle.com/javase/jp/8/docs/api/java/lang/String.html#intern--

⇧おそらく、java.lang.String#intern()メソッドの「文字列のプール」のことを指しているのではなかろうかと、java.lang.Stringのjavadoc(ドキュメント)を見ても「プール」について言及してるのが、java.lang.String#intern()メソッドの部分だけなので。

ただ、例の如く「文字列のプール」については何なのか説明はないという、流石、Oracleさん、安定の不親切さ。

なので、ネット上は大混乱です。

「String Constant Pool」って言葉も出てきたりして、もう情報が錯綜しまくり。だから、あれほどドキュメントは曖昧にするなと言ったのに、って偉い人が言ってくれれば良いんですけどね...

そんなわけで、推測するしかないんだけど、

⇧ おそらく「Current Class Constant Pool Reference」が参照してる「Run-Time Constant Pool」の中の「string constants」って部分が「Pool of Strings」ってことなんじゃないかと。

ただ、「new演算子」でインスタンス化したオブジェクトは「ヒープ」領域に配置されると思われるので、

⇧ String型のオブジェクトってやつは、

の2か所に分散されてるってことみたいね。それぞれのオブジェクトへの参照値ってのは「Current Class Constant Pool Reference」に作成されるんでしょうね。

 

このあたりの検証をされてる方がおりまして、

qiita.com

⇧ 上記サイト様が詳しいです。

 

それにしても、Javaって相変わらず情報が錯綜してますね、公式のドキュメントで記載の無い情報が多過ぎるからだとは思いますが、25年間以上こんな感じってのが絶望的ですね... 

今回はこのへんで。