プロが教える店舗&オフィスのセキュリティ対策術

インスタンス生成時、メモリを確保するためにnewします。
その時に疑問が生まれました。以下の書き方は何が違うのでしょうか。
そしてどちらが推奨されるのでしょうか?

(1) newを明示的に実施
String str = new String();
str = "hoge";
(2) newは明示的にしない
String str = "hoge";

A 回答 (4件)

あー、違う。

けっこう勘違いしている人多いんだけど。

String str = "Hoge";
String str = new String("Hoge");

これは、実は「別のもの」なんだよ。コンパイル時に、"Hoge"がnew String("Hoge")に変換されたりはしない。なぜなら、これはJava内部ではまったく別のことを行っているからだ。実際、コンパイルしたものをデコンパイルしてみるとわかる。"Hello"は”Hello"だし、new Stringはnew Stringのままだ。これらは、シンタックスシュガーじゃない。それぞれ「別のことを行っている文法」なんだよ。

これは、Javaの中でもかなり引っかかる部分なんだが、実は、"Hello"は、「Hello」というStringオブジェクト「ではない」んだ。これは、うーん、Java仮想マシンの仕組みがわからないとうまく説明できないんだが。

ま、手っ取り早くいっちまえば、「Stringリテラルは、Javaの内部では特別なものとして扱われている」ということ。String str = "Hello";みたいにソースコード内にStringリテラルが登場すると、Java仮想マシンは定数プールと呼ばれるところにその値を保管し、次に同じリテラルが登場するとその定数プールに保管した値の参照を変数に渡す。つまり、

String a1 = "Hello";
String a2 = "Hello";

こんなふうにすると、a1にもa2にも常に同じオブジェクトへの参照が渡される(つまりどちらの変数も同じオブジェクトを見ている)。ところが、

String b1 = new String("Hello");
String b2 = new String("Hello");

このようにnew Stringすると、Java仮想マシンは、定数プールではなく、通常のオブジェクトを配置するヒープ内に新たにインスタンスを作成し、その参照を設定する。つまりこの場合、b1とb2は、それぞれ別のStringオブジェクトを参照していることになる。ためしに、

System.out.println(a1 == a2);
System.out.println(b1 == b2);
System.out.println(a1 == b1);

このように、変数の参照が等しいかどうかをチェックすると、a1とa2は等しいが、b1とb2は等しくないし、またa1とb1も等しくないことがわかる。これらは、それぞれ別のオブジェクトを参照してるんだ。いずれもテキストとしての値はすべて「Hello」なんだが、内部的にはまったく別のものだ。

というわけで、特別な理由がない限り、Stringを変数に設定する場合は、String str = "Hello";というようにリテラルを直接指定し、new Stringは使わない。そうすることにより、Stringオブジェクトを必要最低限で済ませることができ、メモリにもまたパフォーマンス的にもよい結果となる(ま、実際はほとんど違いはないけどな)。

ただし、この「StringリテラルとStringインスタンスは別のものだ」ということを利用して、わざとnew Stringを使うこともある。が、このへんは、もう少しJavaに慣れてから知ればいいことだろう。
    • good
    • 12
この回答へのお礼

すっごい勉強になりました^^
ありがとうございます。結構むずかしいですねぇ。。

お礼日時:2009/06/30 11:21

回答#3を拝見して私の認識も今まで違っていたことが分かりました。


失礼しました。

リテラルプールにStringリテラルが格納されて、重複するリテラルについてはその参照がプール内に1つだけコピーが保持されるんですね。
納得しました。

ありがとうございます。

参考URL:http://codezine.jp/article/detail/2915
    • good
    • 0

Javaではソースコードのコンパイル時に、自動的にソースコードが変換・付加されるものがいくつかあります。



String str = "hoge";

もその1つです。実際にコンパイルされる時ときには

String str = new String("hoge");

と変換されコンパイルされます。

その他、クラス内にデフォルトコンストラクタ(引数なしのコンストラクタ)を実装しなかった場合、コンパイル時に自動的に付加されたりします。
    • good
    • 0
この回答へのお礼

ありがとうございます!自動的に付加されるものって多いですよねー
サブクラスのコンストラクタで、スーパークラスのコンストラクタが自動で呼び出されるとか。結構そこで迷っちゃいます><

お礼日時:2009/06/16 14:10

「""」で囲った構文というのは



"hoge" と、new String("hoge") は、まったく同じ意味として解釈されます。
"hoge"と書くと、自動的にString型の実体をnewで作っているのと同じです。

つまり、(1)の一行目、
String str = new String();
は、少しムダな処理をしていることになります。
ここでメモリを確保してString型の新しい実体を生成していますが、
次の行ではメモリの別の場所に確保された別の実体が割り当てられ、
結果的に、1行目で作ったほうの実体はガベージコレクションで破棄されてしまいます。

(1)のように書くのなら、
String str = null;
str = "hoge";
このようにするのが良いです。
    • good
    • 0
この回答へのお礼

ありがとうございます。では(2)のほうが良いのですねー。
勉強になりました!

お礼日時:2009/06/16 14:08

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!