文字列のように「不変」など多くの便利な機能は、芸術のエンジニアうまく設計された作品です!脆弱アートワーク!最終的で、それは世界のクマの子供、セーフガード世界平和の破壊を防止するために、継承を拒否することです!
1.は不変とは何ですか?
文字列不変元のメモリアドレスのデータを変更しない、第二の「abcedl」に割り当てられた「ABCD」既存の文字列に、示されるように、単純であるが、再点新しいオブジェクト、新しいアドレス。
なぜ2.文字列の不変?
JDKのオープンソースは、java.lang.Stringで最初の3行をクラスの手を、このように書かれています:
-
public final class String implements java.io.Serializable, Comparable<String>, CharSequence {
-
/** String本质是个char数组. 而且用final关键字修饰.*/
-
private final char value[];
-
...
-
...
-
}
最初の文字列クラスは、文字列を継承することができない示す、最終的なキーワードによって変更されます。以下を見て、主部材フィールド値文字列クラスは、char []配列が、である最終的な修飾。決して変更を作成するために、最終的な変更されたフィールドの後。
一部の人々はそれがなかった、この話は終わったと思います。値は不変であるが、それがためにのみ、このアドレスの基準値が変更されません。停止することはできません配列arrayが可変である事実。配列は、図facie。
スタック上だけ参照、ヒープヒープの配列のボディ構造である配列変数。値の最終修正とStringクラスには、これはスタック参照アドレス不変の値と呼ばれていると言うこと除きます。彼は不変の配列データそのものの山を言いませんでした。次の例を見て、
-
final int[] value={1,2,3}
-
int[] another={4,5,6};
-
value=another; //编译器报错,final不可变
最終修正を持つ値は、コンパイラは私がアドレス値に別のヒープを指していることを許可していません。しかし、私の手が直接配列要素に、毎分は、取得した場合。
-
final int[] value={1,2,3};
-
value[2]=100; //这时候数组里已经是{1,2,100}
または粗く直接変更を反映し、それも可能です。
-
final int[] array={1,2,3};
-
Array.set(array,2,100); //数组也被改成{1,2,100}
文字列は不変であるので、キーがある文字列のすべての背後にある方法でSUNのエンジニアは、要素ではなく、露出した内部メンバーフィールドにアレイに触れないように非常に慎重だから。
この文、大きな最終よりも民間への専用アクセスの役割] [民間最終char値。そして、設計者は非常に慎重に、継承を禁止し、他の人々によって受け継が破壊を避けるために、全体の最終的な文字列のセットを置きます。だから、基本的な実装では不変ではなく、最終的なものでキー文字列。テストエンジニア構造データ型、データパッケージスキル。
3.利点は不変何ですか?
最も単純な理由があるため、安全性。
例1
-
package _12_01字符串;
-
public class 为什么String要设计成不可变类你 {
-
public static void main(String[] args) {
-
String a, b, c;
-
a = "test";
-
b = a;
-
c = b;
-
String processA = processA(a);
-
String processB = processB(b);
-
String processC = processC(c);
-
System.out.println(processA);
-
System.out.println(processB);
-
System.out.println(processC);
-
}
-
static String processA(String str){
-
return str + "A";
-
}
-
static String processB(String str){
-
return str + "B";
-
}
-
static String processC(String str){
-
return str + "C";
-
}
-
}
-
//OUTPUT
-
// testA
-
//testB
-
//testC
非文字列変動の支持体は、それらの値は、明確に定義された場合に関係なく、その方法は、互いに独立して、呼び出されます。
文字列が変数である場合には、以下の例では、我々は、シミュレート文字列変数にするStringBufferを使用することも可能です
-
package _12_01字符串;
-
public class 为什么String要设计成不可变类2 {
-
public static void main(String[] args) {
-
StringBuffer a, b, c;
-
a = new StringBuffer("test");
-
b = a;
-
c = b;
-
String processA = processA(a);
-
String processB = processB(b);
-
String processC = processC(c);
-
System.out.println(processA);
-
System.out.println(processB);
-
System.out.println(processC);
-
}
-
static String processA(StringBuffer str){
-
return str.append("A").toString();
-
}
-
static String processB(StringBuffer str){
-
return str.append("B").toString();
-
}
-
static String processC(StringBuffer str){
-
return str.append("C").toString();
-
}
-
}
-
//OUTPUT
-
// testA
-
//testAB
-
//testABC
プログラマの意図が望ましい変数が一定である。B = A、C = bがあることがわかります。安全文字列不変がここに反映さそう。実際には、StringBufferのは、Stringクラスの役割を支持する変数である役割を果たしました。
例2
以下をご覧HashSetの StringBuilderのシーンの要素を行うには、問題はさらに深刻で、より微妙。
-
class Test{
-
public static void main(String[] args){
-
HashSet<StringBuilder> hs=new HashSet<StringBuilder>();
-
StringBuilder sb1=new StringBuilder("aaa");
-
StringBuilder sb2=new StringBuilder("aaabbb");
-
hs.add(sb1);
-
hs.add(sb2); //这时候HashSet里是{"aaa","aaabbb"}
-
StringBuilder sb3=sb1;
-
sb3.append("bbb"); //这时候HashSet里是{"aaabbb","aaabbb"}
-
System.out.println(hs);
-
}
-
}
-
//Output:
-
//[aaabbb, aaabbb]
StringBuilderの変数SB1とSB2は、ヒープリテラル「AAA」と「AAABBB」を指しました。それらをすべてHashSetのを挿入します。この時点で問題ありません。しかし、私は、アドレスSB1に変数SB3の後ろにもポイントを置き、その後、保護のStringBuilderの無い不変性、オリジナルの「AAA」のアドレスに直接SB3変更するのでSB3の値を変更した場合。SB1がまた値が変更された原因となります。この時点で、HashSetのは、二つの同じキー「AAABBB」がありました。破壊HashSetのキーの一意性を。だから、変数の型を行わないのHashMapとHashSetのキー。
不変性サポートスレッドの安全性
我々はすべて知っているが、またそこにリソースを読み込むための複数のスレッドが競合状態になるだろうされていません同時実行シナリオにされています。書き込み操作を行うための唯一の資源は危険になります。不変オブジェクトは、書かれたスレッドセーフなので、することはできません。
不変のサポート文字列定数プール
最後に、忘れてはいけない文字列の別の定数プール文字列属性。以下、このような文字列1 と2がリテラル使用されている「何か」の割り当てを。実際に、彼らは同じメモリアドレスを指します。
-
String one = "someString";
-
String two = "someString";
したがって多数のストリングは、メモリ空間を節約し、効率を向上させることができる場合です。しかし、この機能を実装することができました、不変の文字列は、基本的な要件です。文字列のメモリ内容を行うために、変更に変更することができますので、もし完全に無意味です。