String&StringBuilder&StringBufferまとめ


一、StringのJVMメモリ分配テストと分析
        
        String a="a";
        String b="b";
        String c="ab";
        String d="ab";
        String e=a+b;
        String f = "a" + "b";
        final String p = "a";
        final String q = "b";
        String m = p + q;
        String n = p + "b";
        String str1 = new String("ab");
        String str2 = new String("ab");
        
        System.out.println("c==d?" + (c==d));
        System.out.println("d==e?" + (d==e));
        System.out.println("c==f?" + (c==f));
        System.out.println("c==m?" + (c==m));
        System.out.println("c==n?" + (c==n));
        System.out.println("d==str1?" + (d==str1));
        System.out.println("str1==str2?" + (str1==str2));
        System.out.println("e==str1?" + (e==str1));

出力結果:
c==d?true
d==e?false
c==f?true
c==m?true
c==n?true
d==str1?false
str1==str2?false
e==str1?false

プログラムにデータを格納するためのメモリは、4つのブロック1、グローバル領域(静的領域)(static)に分けられる.
2、文字定数領域:定数文字列はこの領域に配置され、私たちがよく言う定数プールです.
3、スタック領域(stack):関数のパラメータ値、局所変数の値などを格納します.
4、ヒープエリア(heap):オブジェクトを保存する
文字列を定義すると
String a = "a";
aスタック領域では、「a」は文字列定数であり、定数プールでは
String b = "b";
bスタック領域、「b」定数プール
String c="ab";
cスタック領域、「ab」定数プール
String d="ab";
dスタックエリアでは、この時点で定数プールにすでに「ab」があるので、既存の「ab」をそのまま使用します
だからこの時cとdが指す定数プールの中の同じ「ab」
String e=a+b;
eスタック領域では、a+bは実際に新しいStringオブジェクトを生成し、Stringオブジェクトである以上、結果として「ab」はスタック領域に置かれ、すなわちeはスタック内の「ab」を指す
この場合、c=dはtrue、c=eはfalse
////////////////////////////////////
また、文字列オブジェクトが定義されている場合は
String str1 = new String("ab");
str 1はスタック領域にあり、作成された「ab」文字列オブジェクトはスタック領域にある
String str2 = new String("ab");
str 2はスタック領域にあり、また作成された新しい「ab」オブジェクトもスタック領域にありますが、さっきの「ab」とは同じではありません.
スタック領域に2つの文字列オブジェクトがあるに相当しますが、ちょうど内容が「ab」です.
だからstr 1=str 2はfalse
定数プールに置かれている定数文字列は繰り返し使用できますが、a+bのような形式では結果は「ab」ですが、使用する文字列定数「ab」ではありません.
String e=a+bについては、コンパイラによって最適化された結果「ab」となると、コンパイラは定数プールから直接「ab」定数を取り出し、eに参照を付与するという説もある.私が使っているJDKは1.6.0_34,得られた結果はd=e?falseは、このバージョンのJVMが上記のコンパイラ最適化を行っていないことを示しています.
(後期修正:String e=a+bの場合.コンパイラには最適化が存在する.ただし、コンパイラの最適化はコンパイル期間であり、aとbは変数文字列であるため、コンパイル期間ではその具体的な値を特定できないため、コンパイル期間は最適化できない.aとbがfinal修飾を使用して初期値が付与されている場合、すなわちaとbが初期値のある定数文字列であれば、コンパイル期間でその値を特定することができ、コンパイラはeの値を「ab」に最適化する.JVM定数プールと文字列最適化のより詳細な説明については、私のもう一つの転載博文を参照してください:JVM定数プールと8種類の基本データと文字列、これは私が今まで見たものです.
定数プールと文字列の最も徹底した解釈.)
以上のほとんどの内容を抜粋したhttp://blog.sina.com.cn/s/blog_4b622a8e0100c296.html処の分析.
二、StringBuilder&StringBuffer
以下の2つの招待状を見て、すべてとても詳しく書いて、みんなは見てみることができます:
http://blog.csdn.net/kingzone_2008/article/details/9220691
http://www.cnblogs.com/dolphin0520/p/3778589.html
ソースコードを見て、自分の少しの理解:
1)
StringBufferはスレッドが安全で、StringBuilderは非安全で、ほとんどの場合マルチスレッドの問題を考慮する必要はありませんので、StringBuilderを使うと効率は少し高くなりますが、マルチスレッドが必要な場合はStringBufferを使用します.以下の英語はStringBuilderソースコードの注釈で、使用アドバイスも提供されています.
This class provides an API compatible
 * with StringBuffer, but with no guarantee of synchronization.
 * This class is designed for use as a drop-in replacement for
 * StringBuffer in places where the string buffer was being
 * used by a single thread (as is generally the case).   Where possible,
 * it is recommended that this class be used in preference to
 * StringBuffer as it will be faster under most implementations.
2)
        StringBuilder sb  = 
new 
StringBuilder();
        sb.append( 
"AAAA"
);
        String appendStr = 
null
;
        sb.append(appendStr);
        sb.append( 
"BBBB"
);
        System. 
out
.println( 
"sb:" 
+ sb.toString());
コンソール出力結果:
sb:AAAAnullBBBB
これはappendメソッドの場合、パラメータがnullの場合、StringBuilder&StringBufferの処理はデフォルトでsbの後ろに「null」文字列を追加するためです.