Javaの学習の過程で、我々は、String型が不変になるように設計されて語られます。なぜ文字列は、Java開発者は、このような特別な治療を持っているのですか?最終的には彼らの設計意図や設計コンセプトは何ですか?だから、私は文字列を解析するために、次の3つの質問をしました:
文字列本当に不変?
実装の基礎となる文字列:
パブリック最終クラスString java.io.Serializableの、<string>に匹敵たCharSequenceは{実装します / **値は、文字の保存に使用されています。* / 民間最終char値[]。 / **キャッシュ文字列のハッシュコード* / プライベートint型のハッシュ。//デフォルトは0 //他のコード }
文字列は、基本となる実装に依存している、それは変数の型を基に依存していることから、それから彼は、Java開発者が技術によって実現するのでそれは、文字列のユーザーから切り離さなぜ変数、文字列の不変の理由でなければならない、のchar []配列であります基礎となるデータの操作。しかし、我々は反射機構と、基本となる文字列の操作は、その不変の推測をテストすることができます。
反射的文字列:
//文字列の「Hello World」を作成し、Sを参照するために割り当てられました
文字列s = "Hello World" の。
System.out.println( "S =" + S)。// こんにちは世界
// Stringクラスのフィールドの値を取得します。
フィールドvalueFieldOfString = String.class.getDeclaredField( "値")。
//プロパティアクセスの値を変更
valueFieldOfString.setAccessible(真の);
//オブジェクトsのプロパティの値を取得します。
[]値=(CHAR [])valueFieldOfString.get(S)char型。
//最初の5つの文字で参照値の配列を変更
値[5] = '_'。
System.out.println( "S =" + S)。//こんにちは世界
二つの文字列による出力は、我々が見ることができ、文字列が変更されましたが、コードの中で、ほとんど反射メカニズムは文字列を操作するために使用されていないので、私たちは、String型と考えるだろう不変です。
なぜ文字列は不変として設計されます
-
セキュリティ
-
安全上の懸念を提起、例えば、データベースのユーザー名とパスワードは、データベースへの接続を取得するために、文字列の形で渡される、またはソケットプログラミングでは、ホスト名とポートは、文字列として渡されます。そうでない場合は、ハッカーが抜け穴をドリルダウンすることができ、文字列は不変なので、その値は変更できないため、オブジェクトの値を変更する文字列、セキュリティホールを指摘
-
同時実行シナリオ、複数のスレッドで保証スレッドの安全性を同時に読み込み、リソースを書き、文字列は不変であるため、競合状態をリードする、スレッドとそのスレッドを確保するために問題を引き起こすことはありません
-
ハッシュコード、文字列が作成されると、ハッシュコードもキャッシュされ、関連する計算ハッシュコードの値、文字列変数場合、ハッシュコードはまた、地図、セットや他のコンテナでのために、彼らのキーを変更します独自性と一貫性を確保する必要性は、それゆえ、不変の文字列は、それがより適切なときに、他のオブジェクトよりもコンテナキーにします。
-
-
演奏
-
文字列は不変ですと、文字列定数プールは理にかなっています。文字列定数プールに表示され、実行時のヒープメモリを大幅に節約するために、文字列でプールに異なる基準点となるよう、同じ文字列リテラルを作成するために減少させることができます。文字列変数、文字列定数プール無意味、ベースString.intern定数プール()メソッドも失敗した場合、あなたは新しい文字列を作成するたびに、ヒープに新しいスペースを開くより多くのメモリを占有します
-
サンプルコード:
不変の文字列:
公共の静的な文字列appendStr(文字列S){ S + = "BBB"; 返却値; } //変数のStringBuilder パブリック静的StringBuilderのappendSb(のStringBuilder SB){ sb.append( "BBB")を返します。 } パブリック静的無効メイン(文字列[] args){ 行うには、//文字列パラメータ 文字列s =新しい文字列( "AAA"); ストリングNS = Test.appendStr(S)。 System.out.println( "文字列AAA >>>" + s.toString()); // AAA //引数としてのStringBuilder StringBuilderのSB =新しいStringBuilderの( "AAA")。 StringBuilderのNSB = Test.appendSb(SB)。 System.out.println( "のStringBuilder AAA >>>" + sb.toString()); // AAABBB }
文字列不変技術
オープンJDKのソースコード:
パブリック最終クラスString java.io.Serializableの、<string>に匹敵たCharSequenceは{実装します / **値は、文字の保存に使用されています。* / 民間最終char値[]。 / **キャッシュ文字列のハッシュコード* / プライベートint型のハッシュ。//デフォルトは0 //他のコード }
-
キーワードの最終によって変更Stringクラスは、クラスは継承できません説明しました
-
属性は、最終修正することができる[] CHAR値は、基準値を作成した後、変更することができない説明しました
上記2点を完全に不変ストリングを実現することができない、なぜなら。
最終INT []の値= {1,2,3} INT []別= {4,5,6}。 値=別; //コンパイルエラー、最終不変
最終値は、参照のみが変更されないことを保証するために、改変が、配列は値のヒープに指摘され、本当のデータ限り、アレイヒープの動作、静止画データを変更することができるです。[説明:文字列は、実際には変数です]
最終INT []の値= {1,2,3}。 値[2] = 100; //これはアレイがある場合、{1,2,100}
-
私有財産のすべてのメンバーは、キーワードを変更しています
不変の文字列を達成するために、キーは、文字列の設計・開発プロセスにJava開発者にあるAPIはまったく値演算値を持たないように設計されている間(代わりに新しい文字列を使用しての、いずれかの内部のメンバーを公開していなかった)の道不変の文字列ことを確認するために、新しい文字列を返します。
JDK文字列APIのソースコード:
パブリック静的文字列のvalueOf(チャーC){ CHARデータ[] = {C}。 新しい文字列方式を返す)(//新しい文字列を使用し、新しい文字列(データ、true)を返します } パブリック文字列連結(文字列str){ INT otherLen = str.length()。 IF(otherLen == 0){ これを返します。 } int型のlen = value.length。 チャーBUF [] = Arrays.copyOf(値、LEN + otherLen)。 str.getChars(BUF、LEN)。 新しい文字列方式を返す)(//新しい文字列を使用し、新しいString(BUF、true)を返します }
他の人たちによって継承継承する最終セット全体で禁止された文字列は、損傷を避けます。だから、キー文字列ではなく、最終的なよりも、基本的な実装では不変です。テストエンジニア構造データ型、データパッケージスキル。