web-dev-qa-db-ja.com

「new String()」も不変ですか?

私はJava Stringをしばらく勉強しています。以下の質問は、以下の投稿に基づいています

Java文字列は特別です
Javaでの文字列の不変性

  1. 不変性:不変性により、Stringクラスはcommon poolの値を他の場所/変数で再利用できるように設計されました。これは、Stringが次のように作成された場合に有効です。

    _String a = "Hello World!";_ただし、次のような文字列を作成すると

    String b = new String("Hello World!");なぜこれも不変なのですか? (またはそれは?)。これには専用のヒープメモリがあるため、他の変数に影響を与えることなくこれを変更できるはずです。設計上、String全体が不変と見なされる理由は他にありましたか?または、上記の仮定は間違っていますか?

  2. 2つ目の質問は、共通文字列プールについてでした。文字列オブジェクトを次のように作成すると

    _String c = "";_はプールに空のエントリが作成されていますか?

これらに関する投稿は既にありますか?もしそうなら、誰かがリンクを共有できますか?

72
Some guy

new String()String ...を生成する式であり、Stringは生成方法に関係なく不変です。

new String()が可変かどうかを尋ねるのは無意味です。それはプログラムコードであり、値ではありません。しかし、それはあなたが本当に意味するものではないと思います。)


String c = "";として文字列オブジェクトを作成すると、プールに空のエントリが作成されますか?

はい;つまり、空の文字列のエントリが作成されます。空のStringについて特別なことはありません。

(コードを実行するずっと前に、""のプールエントリが作成されます。実際には、コードが読み込まれたときに作成されます...または場合によってはそれよりも前です。)


だから、新しいヒープオブジェクトも不変であるかどうかを知りたいと思っていました...

はい、そうです。ただし、不変性はStringオブジェクトの基本的なプロパティです。すべてのStringオブジェクト。

String AP​​Iには、Stringを変更するためのanyメソッドがありません。だから(いくつかの危険で愚かなことは別として1 リフレクションを使用したトリック)、Stringを変更することはできません。

もしそうなら、目的は何でしたか?.

Java Stringが不変クラスとして設計されている理由は単純です。コア文字列クラスの場合、正しいプログラムを記述し、他の人のコードを読んだり理由付けたりしやすくなります。不変のインターフェイスを提供します(または、少なくとも、これがこの設計上の決定の理由です、私は理解しています)。

答えを聞いてみると、同じ変数への他の参照が理由の1つであることがわかります。私がこれを理解するのが正しいかどうか私に知らせてください。

いいえ。それはそれよりも基本的です。単純に、すべてのStringオブジェクトは不変です。これを理解するのに必要な複雑な特殊なケースの推論はありません。それは>> is <<です。

レコードについて、Javaで可変の「文字列のような」オブジェクトが必要な場合は、StringBuilderまたはStringBufferを使用できます。しかし、これらは文字列とは異なるタイプです。


1-これらのトリックが(IMO)危険で愚かである理由は、文字列プールを介してアプリケーションの他の部分と共有される可能性のある文字列の値に影響を及ぼすためです。これは混乱を引き起こす可能性があります...あなたのコードを保守する次の人が追跡する可能性がほとんどないという点で。

105
Stephen C

文字列は、インスタンス化の方法に関係なく不変です。

1)短い答えはyesnew String()も不変です。

なぜなら、あなたはreplaceで実行するすべての可能な可変操作toLowerCaseString etcetraなど) 元のに影響を与えず、Stringインスタンスを返し、新しいインスタンスを返します

JavadocでStringを確認できます。公開されているpublicの各Stringメソッドは、新しいStringインスタンスを返し、メソッドを呼び出した現在のインスタンスを変更しません。

これはマルチスレッド環境で非常に役立ちます。可変性について考える必要がないため(誰かが値を変更するかを渡すか共有するたびに) String周り。 Stringは簡単に最もよく使用されるデータ型になる可能性があるため、設計者は私たち全員に毎回可変性について考えないように祝福してくれ、多くの痛みを軽減しました。

不変性により文字列プールまたはキャッシングが許可されます

他の場所で同じ文字列値が必要な場合、その不変の参照が返されるため、文字列の内部プールが可能だったのは不変プロパティのためです。 Stringが可変だった場合、メモリを節約するためにStringsをこのように共有することはできなかったでしょう。

文字列の不変性はプーリングによるものではありませんが、不変性にはそれに付随する利点があります。

文字列のインターンまたはプーリングは、 Flyweight Design pattern の例です

2)はい、空のStringは他のStringインスタンスと同じくらいStringであるため、他のStringと同様にインターンされます。

参照:

42
Narendra Pathai

Javaライブラリは、オブジェクトの構築方法に関係なく、Stringオブジェクトが不変であるという制約を中心に大幅に最適化されます。bを使用してnewを作成する場合でも、そのインスタンスに渡す他のコードこれは、値を不変として扱いますこれは、Value Objectパターンの例であり、すべての利点(スレッドセーフ、プライベートコピーを作成する必要がない)が適用されます。

空の文字列""は他のすべてと同じ正当なStringオブジェクトです。たまたま内部コンテンツがなく、コンパイル時の定数文字列はすべてインターンされているため、一部のランタイムライブラリが既に追加されていることを事実上保証します。プール。

18
chrylis

1)不変部分は、プールのbecauseではありません。そもそもプールが可能になるだけです。多くの場合、文字列は引数として他の関数に渡されるか、他のスレッドと共有されます。文字列を不変にすることは、そのような状況で推論を容易にするための設計上の決定でした。 yes-JavaのStringsは、作成方法に関係なく常に不変です(Javaに変更可能な文字列を含めることができることに注意してください) _-Stringクラスではありません)。

2)はい。多分。私は実際に100%確信しているわけではありませんが、そうであるべきです。

14
Cubic

Java Oracleドキュメント から:

文字列は定数です。 それらの値は、作成後に変更することはできません

そしてまた:

文字列バッファは可変文字列をサポートします。 Stringオブジェクトは不変であるため、共有できます。

一般的に言って、「すべてのプリミティブ」(または関連する)オブジェクトは不変です(形式主義の欠如を受け入れてください)。

Stack Overflowの関連記事:

オブジェクトプールについて:オブジェクトプールはJava最適化であり、不変にも関連していません。

7
venergiac

これは厳密にはあなたの質問への答えではありませんが、もしあなたの質問の背後に操作可能な可変文字列を持ちたいのであれば、StringBuilderクラスをチェックアウトする必要があります。 Stringには、現在のコンテンツを変更するメソッドも追加されています。

満足できるような方法で文字列を作成したら、それに対してtoString()を呼び出すだけで、それを通常のStringに変換して渡すことができますStringsのみを受け取るライブラリルーチンおよびその他の関数。

また、StringBuilderStringの両方がCharSequenceインターフェイスを実装しているため、変更可能な文字列と不変の文字列の両方を使用できる独自のコードで関数を記述したい場合は、それらを宣言できますCharSequenceオブジェクトを取得します。

7
Dolda2000

String is immutableは、作成方法に関係なくオブジェクト自体を変更できないことを意味します。2番目の質問に関しては、「はい」はエントリを作成します。

6
Kick

実際には逆です

[...] Stringクラスは、共通プールの値を他の場所/変数で再利用できるように設計されています。

いいえ、Stringクラスは不変であるため、プログラムの別の部分から変更されることを心配せずに、そのインスタンスを安全に参照できます。これが、そもそもプーリングが可能な理由です。

だから、これを考慮してください:

// this string literal is interned and referenced by 'a'
String a = "Hello World!";

// creates a new instance by copying characters from 'a'
String b = new String(a);

さて、新しく作成したb変数への参照を単に作成するとどうなりますか?

// 'c' now points to the same instance as 'b'
String c = b;

c(または、より具体的には、それが参照しているオブジェクト)を別のスレッドのメソッドに渡し、メインスレッドの同じインスタンスで作業を続けることを想像してください。そして、文字列が可変だったらどうなるか想像してみてください。

とにかくこれはなぜですか?

他に何もないとしても、それは不変オブジェクトがマルチスレッドをはるかに簡単にし、通常はさらに高速にするためです。異なるスレッド間で可変オブジェクト(可変のプライベート/パブリックフィールドまたはプロパティを持つステートフルオブジェクト)を共有する場合、同期アクセス(ミューテックス、セマフォ)を確保するために特別な注意を払う必要があります。この場合でも、すべての操作で原子性を確保するには特別な注意が必要です。マルチスレッドは難しいです。

パフォーマンスへの影響については、文字列全体を新しいインスタンスにコピーして、1文字でも変更することは、スレッドセーフアクセスを確保するために必要な同期コンストラクトにより、高価なコンテキストスイッチを誘発するよりも実際に速いことに注意してください。また、既に述べたように、不変性はインターンの可能性も提供します。つまり、実際にはメモリ使用量の削減に役立ちます。

一般的には できる限り不変なものを作成する にすることをお勧めします。

5
Groo

1)不変性:文字列は、セキュリティ上の理由で新しい方法または他の方法を使用して作成した場合、不変になります

2)はい、文字列プールに空のエントリがあります。

コードを使用して概念をよりよく理解できます

    String s1 = new String("Test");
    String s2 = new String("Test");
    String s3 = "Test";
    String s4 = "Test";

    System.out.println(s1==s2);//false
    System.out.println(s1==s3);//false
    System.out.println(s2==s3);//false
    System.out.println(s4==s3);//true

これがクエリに役立つことを願っています。リンクをよりよく理解するために、Stringクラスのソースコードをいつでも確認できます。 http://grepcode.com/file/repository.grepcode.com/Java/root/jdk/openjdk/6-b14/Java /lang/String.Java

4
nikhilgupta86

作成された文字列は、作成方法に関係なく常に不変です。

質問への回答:

  1. 唯一の違いは次のとおりです。
    ストリングが-_{String a = "Hello World!";}_のように作成されると、1つのオブジェクトのみが作成されます。
    そして、-{String b = new String("Hello World!");} then two objects get getのように作成されます。 'new'キーワードを使用したため、最初の1つ、およびStringプロパティのために2つ目。

  2. はい、確かに。プールに空のエントリが作成されます。

2
Arbind

1-Stringimmutableです。

Java文字列は本当に不変ですか?

そのため、さまざまな方法で作成できます。

2-短い答え:はいは空になります。

2
user1968030

不変性はnewの機能ではなく、クラスStringの機能です。ミューテーターメソッドがないため、不変です。

1
fastcodejava

文字列は変更する手段を提供しないため、不変です。これは、改ざんを防ぐための設計です(最終的なものであり、基礎となる配列に触れることは想定されていません...)。

整数は、変更する方法がないため、不変です。

作成方法は関係ありません。

1
njzk2
 String A = "Test"
 String B = "Test"

文字列B called "Test" .toUpperCase()which change the same object into"テスト", soAwill also be "TEST" `は望ましくありません。

1
Surya Rawat

あなたの例では、参照が変更され、それが参照するオブジェクトではないことに注意してください。つまり、参照としてのbが変更され、新しいオブジェクトを参照する場合があります。しかし、その新しいオブジェクトは不変です。つまり、コンストラクターを呼び出した後、その内容は変更されません。

_b=b+"x";_またはb=new String(b);を使用して文字列を変更できます。変数aの内容は変更されているように見えますが、参照(ここでは変数b)とそれが参照しているオブジェクトの不変性を混同しないでくださいto(Cのポインターを考えてください)。参照が指しているオブジェクトは、作成後も変更されません。

参照を変更する代わりに、オブジェクトの内容を変更して文字列を変更する必要がある場合は、Stringの可変バージョンであるStringBufferを使用できます。

0
Sohail Si