文字列を変数として扱う場合、こんなふうに書くことが多いと思う。
まず、ここで宣言しているstrはString型のオブジェクト変数だということに注意。オブジェクト変数はintやcharなどのプリミティブ変数とは違って、「参照」を格納するために使われる。つまり、strという変数に入っているのは、"がちょ〜ん"という文字列そのものではない。この文字列を保持しているString型オブジェクトがシステムの中のどこか(おそらくはメモリ上)に作られ、その場所を表す値(これを参照という)をstrの中に入れているのだ。
ここまでは、たいていの入門書に書いてある。
さて、ここからが本題。String型のオブジェクトを作っているのにコンストラクタを呼ばなくていいのはなぜか? StringクラスのAPIリファレンスを見ると、「String(String original)」というコンストラクタがある。暗黙のうちにこいつが呼ばれているのだろう、と私は考えた。つまり
かと言って、String型オブジェクトを作る際にコンストラクタを呼ぶのは常にで無駄である、というわけではない。StringクラスのAPIリファレンスを見ると、びっくりするぐらいいろいろなコンストラクタがあり、それぞれに想定された使い方があるのだ。最近、その中の1つを使えばUnicodeの文字列を簡単にShift_JISに変換できることを知った。
Javaの文字列は意外に奥が深いミステリーゾーンである。
String str = "がちょ〜ん";
このコードでは、strという変数=入れ物を用意して、その中に"がちょ〜ん"という文字列を入れている、かのように見える。ところが、実際に起こっていることはそれほど単純ではない。まず、ここで宣言しているstrはString型のオブジェクト変数だということに注意。オブジェクト変数はintやcharなどのプリミティブ変数とは違って、「参照」を格納するために使われる。つまり、strという変数に入っているのは、"がちょ〜ん"という文字列そのものではない。この文字列を保持しているString型オブジェクトがシステムの中のどこか(おそらくはメモリ上)に作られ、その場所を表す値(これを参照という)をstrの中に入れているのだ。
ここまでは、たいていの入門書に書いてある。
さて、ここからが本題。String型のオブジェクトを作っているのにコンストラクタを呼ばなくていいのはなぜか? StringクラスのAPIリファレンスを見ると、「String(String original)」というコンストラクタがある。暗黙のうちにこいつが呼ばれているのだろう、と私は考えた。つまり
Integer x = new Integer(200);
みたいな感じでString str = new String("がちょ〜ん");
と同じだろうと解釈したのだ。自著にもそう書いた。しかしこれは間違いである。APIリファレンスには次のように書かれている。String str = "abc";
は、次と同じです。
char data[] = {'a', 'b', 'c'};
String str = new String(data);
つまり、ダブルクオートで囲まれた文字列が「現れた時点」で既にオブジェクトが作られているのである。私の書いたコードでは、これを更にコンストラクタに渡しているわけで、全く無駄なことをしていることになるのだ(がちょ〜ん)。は、次と同じです。
char data[] = {'a', 'b', 'c'};
String str = new String(data);
かと言って、String型オブジェクトを作る際にコンストラクタを呼ぶのは常にで無駄である、というわけではない。StringクラスのAPIリファレンスを見ると、びっくりするぐらいいろいろなコンストラクタがあり、それぞれに想定された使い方があるのだ。最近、その中の1つを使えばUnicodeの文字列を簡単にShift_JISに変換できることを知った。
Javaの文字列は意外に奥が深いミステリーゾーンである。
投稿:竹形 誠司[takegata]/2006年 11月 11日 15時 19分
/更新:2006年 11月 11日 22時 15分
RE:String型のオブジェクトを作るときに、なぜコンストラクタを呼ばないのか?
by KILROY[KILROY]
ついでながら、『Web アプリケーション構築入門』の P.50 に「文字列を連結する場合は、+ 演算子を使うより StringBuffer の append メソッドを使ったほうが高速だと云われている。」とありますが、式の右辺に出てくる String 同士の + は、コンパイラによって大抵 append メソッドで置き換えられています。
ループの中で String に対してストリングを += する場合はそうはゆかないので、append メソッドを使うのがよいのですが、 StringBuffer はスレッドセーフではあるものの若干遅いため、メソッドの中でローカルに使うのであれば、スレッドセーフではないが高速な StringBuilder を使うのがナイスです。
ループの中で String に対してストリングを += する場合はそうはゆかないので、append メソッドを使うのがよいのですが、 StringBuffer はスレッドセーフではあるものの若干遅いため、メソッドの中でローカルに使うのであれば、スレッドセーフではないが高速な StringBuilder を使うのがナイスです。
投稿:KILROY[KILROY]/2007年 03月 25日 10時 22分
/更新:2007年 03月 25日 10時 22分