質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

Q&A

解決済

2回答

5241閲覧

コンスタントプールに関して

sususu

総合スコア99

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

2グッド

1クリップ

投稿2018/05/06 15:28

いつもお世話になっております。
コンスタントプールの仕組みがいまいちわかりません。
下記のコードにはなぜコンスタントプールが適用されないのでしょうか?
結果は false:trueです。

package zzz; public class ZZZ { public static void main(String[] args) { String str = "apple"; String[] array = {"a","p","p","l","e"}; String result = ""; for(String val : array){ result = result + val; } boolean a = str == result; boolean b = str.equals(result); System.out.println(a + ":" + b); } }

普段『==』は参照先が同じでない限りfalseを返し
そしてStringに関しては中身が違くともコンスタントプールの仕組みでtrueが返る
と理解していました。
説明文に
『このコンスタントプールは文字列リテラルを使った時だけ有効です』と書いてあります。
上記のコードだとstrもresultもString型だからtrue:trueかと思っていましたがどこの解釈がいけないのでしょうか?
すいませんがどなたかご教授お願いいたします。

K-pgm, ATTOMAN👍を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

ベストアンサー

ソース上にある"abc"のような文字列リテラル(文字列定数と思ってもいいですが)は同じ内容なら同じインスタンスを指すのですが、演算して新たなインスタンスが生成されるともはやそれはリテラルではなくなります。

(A) String a = "abc";

aにはリテラルの参照が入っています。

(B) String a = "ab" + "c";

このような単純ケースもコンパイラーがコンパイル時に連結演算をやってくれるためリテラルの参照がaに入ります。しかし

(C)

Java

1String a1 = "ab"; 2Stirng a2 = "c"; 3String a = a1 + a2;

このくらいになるともはやコンパイラーは「aの中身が"abc"になるはず」という推論をあきらめちゃいます。そのため実行時に演算することになりますが、文字列を連結した演算結果であってリテラルの参照にはなりません。

文字列リテラルが同一のインスタンスになる仕組みはコンパイラーがクラスをロードしたとき、クラスファイルの中に含まれる「ソース上に記述した文字列リテラル」を全てString#internで同一のStringインスタンスに集約する手間をかけているからです。

String#internはそれなりに高速ではありますが、無視してよいほど高速なわけではありません。

(C)のような演算結果"abc"という文字列をString#internにより定数プールへ登録するような真似をするとJavaプログラム全体が致命的な速度低下を招くだろうと思います。それゆえ演算結果はinternされず結果としてコンスタントプールに存在する文字列リテラルと(例えたまたま内容が一致していたとしても)「異なるインスタンス」となると思ってください。


追記:コンパイル時に連結されるケースに配慮して説明を変更しました。

投稿2018/05/06 15:43

編集2018/05/06 15:56
KSwordOfHaste

総合スコア18394

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

KSwordOfHaste

2018/05/06 15:54 編集

失礼しました。上の回答にあるような単純ケースでは"abcd"という文字列リテラルとして認識されます。つまりコンパイル時に連結演算が行われます。しかしもっと複雑なコードでは結果が"abcd"になるかどうかをコンパイラーが計算しきれないため、演算は実行時に行われ結果として上の回答のようになります。 --- 回答本文を訂正いたしました。
sususu

2018/05/06 16:08

具体的な説明どうもありがとうございました!同じインスタンスかどうかを判断して登録するタイミングは、メソッドとかを実行しながらではなくクラスをロードするもっと最初の方の段階ということですね ! 補足まで丁寧にありがとうございます! コードだけではなくjavaの仕組みも覚えていかないと実感しました! ありがとうございました!
KSwordOfHaste

2018/05/06 16:11 編集

> メソッドとかを実行しながらではなくクラスをロードするもっと最初の方の段階ということ おっしゃるとおりです。実行の最初に一度だけやることのオーバーヘッドは許容するわけです。Javaの仕組みというよりはこの考え方は多くの言語でも共通です。オーバーヘッドを最小にしようとするのはどの設計者でも考えますのでどれも似たような方式になるのだと思います。
sususu

2018/05/06 16:21

プログラミング言語に共通することだったのですね!今回流れがわかってスッキリしました。これで寝れそうです! ありがとうございました、また質問あるときはよろしくお願いいたしますm(__)m
guest

0

コンパイラはまだそんなに賢くないので、strとresultのナカミが同一とは判断できないためですね

投稿2018/05/06 15:38

y_waiwai

総合スコア87774

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

sususu

2018/05/06 15:43

そうなってくると初期値で設定した時しかコンパイラは判断できないということなのでしょうか?
y_waiwai

2018/05/06 15:46

そういうことです。で、演算の途中結果などもあるため、わざわざコンスタントプールの対象にはならないというのはちょっと考えるとわかりますね
y_waiwai

2018/05/06 16:01

さて、遠い将来、コンパイラが賢くなって、コードの解析でstrとresultが同一だと判断できるとしたら、 その時はそのコードのコンパイル結果には、arrayとforは削除され、resultは単なる代入に置き換えられる、ということになりますねー これやられると、ちょっと困りますねw #まあ、それに近いことが現実になってたりして
sususu

2018/05/06 16:16

ご回答ありがとうございました!javaの仕組みも少しづつ覚えていこうと思います! フォローさせていただきますm(_ _)m
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問