- PR -

StringクラスとStringBufferクラスについて

1
投稿者投稿内容
はるな先生
会議室デビュー日: 2002/01/24
投稿数: 8
投稿日時: 2002-01-24 15:31
Java勉強中の初心者です。
もし、ご存知の方がお見えでしたらご教示願います。
Javaの『Stringクラス』は、
『文字列は定数です。この値を作成したあとに変更はできません。』とありますが、
どのような意味なのでしょうか?
(『Java2 Platform Standard Editoon, v1.3 API仕様』より引用)
私が実験してみたところ、

String str = "";
と定義したと想定すると

String str = "123";
というように文字列の値を変更したり

String str += "456";
というように文字列を追加したり

if ( str == "456")
というように比較したりできます。

...できるけど、このように使わない方が良いという事でしょうか?

よろしくお願いします。
miki
大ベテラン
会議室デビュー日: 2001/09/21
投稿数: 174
お住まい・勤務地: 東京都八王子市
投稿日時: 2002-01-24 16:35
>String str = "";
>と定義したと想定すると
>
>String str = "123";
>というように文字列の値を変更したり
>
>String str += "456";
>というように文字列を追加したり

上の例のstrという変数は、それぞれ違う文字列オブジェクトを指しているだけで、同じ文字列の構造を変えているわけではありません。変数はオブジェクト(の参照)を入れる箱のようなものです。

文字列を変更したい場合にはStringBufferを使います。StringBufferは文字どおりバッファなので効率よく文字列操作をおこなうことができます。これも最終的にtoString()を使って新しい文字列を作り出すのであって、オリジナルの文字列を変更するのではありません。

str += "456"; というのはコンパイラが内部で、

str = new StringBuffer().append(str).append("456").toString();

のような展開をしていたと思います。
てくてく
会議室デビュー日: 2002/01/24
投稿数: 2
投稿日時: 2002-01-24 17:04
すでに miki さんがお答えになっていらっしゃるので、
ご質問に対する答えではありませんが、気になった点を。

> if ( str == "456")
> というように比較したりできます。

文字列の比較には Stringクラスのequals() メソッドを使います。
"=="演算子は「同じオブジェクトかどうか」を判定します。

たとえば、

String str1 = "abc";
String str2 = new String(str1);
String str3 = str1;

System.out.println( str1 == str2 );
System.out.println( str1 == str3 );
System.out.println( str1.equals(str2) );

とすると、実行結果は

false
true
true

となります。
このことからも、Stringオブジェクトが意味するもの(この場合 "abc" という文字列)が
同じでも、別々のオブジェクトである、ということが分かります。

ただし、
str1 = "abc";
str2 = "abc";
とすると、コンパイル時に最適化されてしまい
str1 == str2
の結果が true になってしまう場合がありますので、注意してください。

はるな先生
会議室デビュー日: 2002/01/24
投稿数: 8
投稿日時: 2002-01-25 09:12
『miki』さん、『てくてく』さん 大変親切なご指導ありがうございました。

私としては、下記のように理解しました。
私の例で示したところの

String str = "";
String str = "123";
String str += "456";

は、それぞれ、値が不変のオブジェクトを作成し、
str は、それらを指す参照型の変数ということですね。
また、『String str += "456"; 』については、
コンパイラが内部で、StringBufferクラスを利用して、
新しいオブジェクトを作成しており、
『str1 = "abc";
 str2 = "abc";』については、
本来であれば別々のオブジェクトを作成するが、
コンパイラの最適化機能により
str1、str2 とも同一のオブジェクトを指していることがある。
結果として、文字列を変更したい場合は、
StringBufferクラスを利用するのが、高速であり、また安全である。

...申し訳ありませんが、
理解違い、理解不足の場合は、ご指摘ください。
miki
大ベテラン
会議室デビュー日: 2001/09/21
投稿数: 174
お住まい・勤務地: 東京都八王子市
投稿日時: 2002-01-25 09:49
引用が前後しますがお許しください。

>結果として、文字列を変更したい場合は、
>StringBufferクラスを利用するのが、高速であり、また安全である。

結果としてという部分がひっかかります。
文字列の「比較」の話と、StringBufferの話は無関係です(念のため)。

実は、StringBufferを使わないで文字列の連結をしようとしたら、
String.concat()というメソッドを使うこともできます。

str = "123".concat("456").concat("789");

でも、このとき"123456789"という目的の文字列を得るために、"123456"という中間のオブジェクトを作ることになります。StringBufferが高速という意味は、このような中間の不要なオブジェクトを作る必要がないということです。この辺の話は「プログラミング言語Java、第3版」に説明があります。この本は大変良い本なのでお勧めします。

>それぞれ、値が不変のオブジェクトを作成し、
>str は、それらを指す参照型の変数ということですね。

なぜ、不変かという点に疑問が残るかと思います。

文字列を不変にすることで、文字列を参照している各オブジェクトがその文字列が(誰か他のオブジェクトによって知らないうちに)変更される、という心配をしなくてすみます。つまり、プログラムのデザインが単純になります。

もし、自分だけがその文字列が不変であることを保証しようとしたら、文字列のコピーを持つ必要があり、その結果としてシステム内が文字列のコピーだらけになってしまいます。これは、不要な文字列オブジェクトを大量に作ることにつながって、ガーベッジコレクタを起動させパフォーマンスを低下させる要因になります。さらに、他のスレッドが文字列を変更しないことを保証しようとしたら、排他制御をおこなう必要がありますが、これは比較的重たい処理です。このように、値を不変にすることで不要なコピーを防ぎ、排他制御を不要にします。

イミュータブルオブジェクトについては「じゃばじゃば」のホームページに解説記事があります(過去にJavaWorldにも記事が出ていましたがどの号かは忘れました)。googleで「イミュータブル」をキーワードにすれば先頭の方に現れると思います。上の不変オブジェクトの説明は受け売りです。
まりり
ぬし
会議室デビュー日: 2001/12/05
投稿数: 329
投稿日時: 2002-01-25 10:10
> また、『String str += "456"; 』については、
> コンパイラが内部で、StringBufferクラスを利用して、
> 新しいオブジェクトを作成しており、

 コンパイラがStringBufferを使っているわけではありません。
 VMが行っています。

> 『str1 = "abc";
>  str2 = "abc";』については、
> 本来であれば別々のオブジェクトを作成するが、
> コンパイラの最適化機能により
> str1、str2 とも同一のオブジェクトを指していることがある。

こちらは、言語仕様上同一のインスタンスを参照します。
http://www.y-adagio.com/public/standards/tr_javalang/index.htm
3.5.10文字列リテラル を見てみましょう。
(ほんとうは原本にあたるべきですが・・・)


Stringが不変であるというのはわかりにくいですが、
"abcd"を"accd"にしようとして"b"の場所を"c"に書き換える
ことができない、ということですね。
新しく別の場所に"accd"を作って参照先を変えなければいけません。


[ メッセージ編集済み 編集者: まりり 編集日時 2002-01-25 10:12 ]
はるな先生
会議室デビュー日: 2002/01/24
投稿数: 8
投稿日時: 2002-01-25 15:05
『miki』さん『まりり』さんありがとうございました。
Java初心者の私ですが、親切な解説をいただきましたので、
Javaへの理解を深めることができたと思っています。

参考書として、「プログラミング言語Java、第3版」は
早速、本屋で買い求めたいともいます。
また、HP「http://www.y-adagio.com/public/standards/tr_javalang/index.htm 」
についても、今後参考にしていきたいと思います。

何分初心者なので、またお聞きすることがあるかと思います。
そのときにも、ご教示いだだけますようよろしくお願いいたします。
1

スキルアップ/キャリアアップ(JOB@IT)