文字列はJavaのオブジェクトなので、なぜ「new」を使用して作成しないのですか?


104

通常new、次のようにキーワードを使用してオブジェクトを作成します。

Object obj = new Object();

文字列はオブジェクトですが、new作成には使用しません。

String str = "Hello World";

どうしてこれなの?で文字列を作ることはできますnewか?


また、この質問を確認してください。stackoverflow.com
変更

1
文字列リテラルはすでにオブジェクトだからです。
ローン侯爵

1
new String(...)大きな文字列を部分文字列化するときに実装の詳細を回避するために使用されていることに注意してください。これはJava 7で修正され、もう必要ありません。
–ThorbjørnRavn Andersen 2016

私はこの投稿の100人目のいいね!:)
Mukit09

回答:


130

すでに述べたものに加えて、文字列リテラル [すなわち、文字列のよう"abcd"ではないようにnew String("abcd")]抑留されているJavaで-この手段は、あなたが「ABCD」を参照してくださいたびに、あなたは、単一の参照を取得することをStringむしろ新しいものよりも、インスタンスを毎回。したがって、次のようになります。

String a = "abcd";
String b = "abcd";

a == b; //True

しかし、あなたが持っていた場合

String a = new String("abcd");
String b = new String("abcd");

その後、

a == b; // False

(そして、誰かが思い出させる必要がある場合は、常に.equals()ストリングを比較するために使用してください; ==物理的等価性のテスト)。

文字列リテラルのインターンは、2回以上使用されることが多いため、優れています。たとえば、(考案された)コードを考えてみます。

for (int i = 0; i < 10; i++) {
  System.out.println("Next iteration");
}

文字列のインターンがなかった場合、「次の反復」は10回インスタンス化する必要がありますが、現在は1回だけインスタンス化されます。


1
String a = new String( "abcd")を使用することで、同じ内容の2つの文字列がメモリに存在することを意味しますか。
変更

1
正しい-コンパイラは必ずしもそのような文字列がすでに抑止されているかどうかを確認する必要はありません(確かにそうした文字列を記述できますが)。
danben

はい、文字列は不変であり、したがって問題なく共有できるため、この最適化は可能です。共有の「asdf」処理は、「Flyweight」設計パターンの実装です。
Manuel aldana、2010年

不可能だとは誰も言っておらず、保証されていないだけです。それはあなたの反対票でしたか?
danben、2010年

「==オブジェクトの等価性のテスト」とはどういう意味ですか?これは私には本当ではないように見えますが、おそらくあなたはこれが意味しているように思われるものとは異なる何かを意味していました。
Dawood ibnカリーム2014年

32

文字列は、Javaの「特別な」オブジェクトです。Java設計者は、文字列が頻繁に使用されるため、独自の構文とキャッシュ戦略が必要であると賢明に判断しました。あなたが言って文字列を宣言するとき:

String myString = "something";

myStringは、値が「something」のStringオブジェクトへの参照です。後で宣言する場合:

String myOtherString = "something";

Javaは、myStringとmyOtherStringが同じであり、それらを同じオブジェクトとしてグローバルStringテーブルに格納するのに十分なほどスマートです。これは、文字列を変更してこれを行うことができないという事実に依存しています。これにより、必要なメモリの量が減り、比較が速くなります。

代わりに、あなたが書く場合

String myOtherString = new String("something");

Javaは、myStringオブジェクトとは異なる、まったく新しいオブジェクトを作成します。


ちょっと...文字列リテラルのある種の構文サポートの必要性を認識するのに「無限の知恵」は必要ありません。他のほぼすべての深刻なプログラミング言語の設計は、ある種の文字列リテラルをサポートしています。
スティーブンC

12
誇大広告は気絶するように減らされました、キャプテン:)
ジェイミー・マクリンドル

16
String a = "abc"; // 1 Object: "abc" added to pool

String b = "abc"; // 0 Object: because it is already in the pool

String c = new String("abc"); // 1 Object

String d = new String("def"); // 1 Object + "def" is added to the Pool

String e = d.intern(); // (e==d) is "false" because e refers to the String in pool

String f = e.intern(); // (f==e) is "true" 

//Total Objects: 4 ("abc", c, d, "def").

これでいくつかの疑問が解消されることを願っています。:)


文字列d =新しい文字列( "def"); // 1つのオブジェクト+ "def"がプールに追加されます->ここで "def"はまだ存在しない場合にのみプールに追加されます
サウザートン

@southerton意味がない。すでにプールに入っています。コンパイラによってそこに配置されました。
ローン侯爵

@EJPなぜ(e == d)はここでfalseですか?彼らは両方ともプール内の同じオブジェクト「def」を参照していますか?
ラジャ

文字列c = new String( "abc"); // 1オブジェクト...このステートメントは正しいですか?「abc」が定数プールからすでに参照されている場合、interメソッドの使用は何ですか?
Prashanth Debbadwar

6

ショートカットです。当初はそうではなかったが、Javaが変更した。

このFAQはそれについて簡単に述べています。Java仕様ガイドでも説明しています。しかし、私はそれをオンラインで見つけることができません。


2
リンクが壊れており、それが変更されたという他の証拠は知りません。
ローン侯爵

1
@EJP 便利な場合は、まだウェイバックマシンにあります。
アルジャン

6

文字列はいくつかの最適化の対象となります(より良いフレーズが必要なため)。他のオブジェクトとは異なり、Stringには(+演算子の)演算子のオーバーロードもあります。したがって、これは非常に特殊なケースです。


1
+は実際には、StringBuilder.append(..)呼び出しに変換される演算子です。
ウィスキーシエラ2010年

5

通常、不要なオブジェクトを作成しないように文字列リテラルを使用します。new演算子を使用してStringオブジェクトを作成すると、毎回新しいオブジェクトが作成されます。

例:

String s1=“Hello“;
String s2=“Hello“;
String s3= new String(“Hello“);
String s4= new String(“Hello“);

メモリ内の上記のコードの場合:

ここに画像の説明を入力してください


2

Javaでは、文字列は特殊なケースであり、多くのルールは文字列にのみ適用されます。二重引用符により、コンパイラーはStringオブジェクトを作成します。Stringオブジェクトは不変なので、これによりコンパイラーは複数の文字列をインターンし、より大きな文字列プールを構築できます。2つの同一のString定数は常に同じオブジェクト参照を持ちます。これが当てはまらない場合は、new String( "")を使用できます。これにより、実行時にStringオブジェクトが作成されます。以前は一般的だったintern()メソッドが、動的に作成された文字列を文字列ルックアップテーブルに対してチェックするようにしていました。文字列がインターンされると、オブジェクト参照は正規のStringインスタンスを指します。

    String a = "foo";
    String b = "foo";
    System.out.println(a == b); // true
    String c = new String(a);
    System.out.println(a == c); // false
    c = c.intern();
    System.out.println(a == c); // true

クラスローダーがクラスをロードすると、すべての文字列定数が文字列プールに追加されます。


「二重引用符により、コンパイラーはStringオブジェクトを作成します。」過小評価されたコメント
csguy

0

構文糖。の

String s = new String("ABC");

構文はまだ利用可能です。


1
これは正しくありません。s = new String( "ABC")では、s = "ABC"と同じ結果は得られません。danbenのコメントを参照してください。
Steve B.

2
また、皮肉なことに、最初にインラインで「ABC」を表すStringインスタンスを作成し、それをコンストラクタ呼び出しに引数として渡して、同じ値のStringを返します。
Andrzej Doyle

1
このコンストラクターの有効な使用例はですString small = new String(huge.substring(int, int));。これによりchar[]、元のhuge文字列から大きな基礎をリサイクルできます。
Pascal Thivent、2010年

1
@PascalThiventはい、Java 8ではもうありません。G1による自動文字列重複排除や今後の文字列圧縮などの他の最適化に備えて、配列を共有しなくなりました。
eckes

@AndrzejDoyle不正解です。コンパイラーはリテラルのオブジェクトを作成します。
ローン侯爵

0

引き続き使用できますがnew String("string")、文字列リテラルなしで新しい文字列を作成するのは困難です...文字配列またはバイトを使用する必要があります:-)文字列リテラルには、1つの追加プロパティがあります。インスタンス(彼らは抑留されています)。


0

リテラル(引用符で囲まれた文字)は、ホストクラスが読み込まれたときに作成されたStringオブジェクトであるため、文字列を新しく作成する必要はほとんどありません。リテラルとドンでメソッドを呼び出すことは完全に合法です。主な違いは、リテラルによって提供される利便性です。charsの配列を作成し、charをcharごとに入力し、新しいString(char array)を実行しなければならない場合、大きな問題であり、時間の無駄になります。


0

新しい文字列を自由に作成してください

String s = new String("I'm a new String");

通常の表記法s = "new String";は多かれ少なかれ便利なショートカットです-これは、方程式の条件を満たす文字列が本当に必要なかなりまれなケースを除いて、パフォーマンス上の理由で使用する必要があります

(string1.equals(string2)) && !(string1 == string2)

編集する

コメントへの応答:これは助言を意図したものではなく、質問者の論文に対する単なる直接的な応答であり、であり、文字列に'new'キーワード使用ていません。これは単に真実ではありません。この編集(上記を含む)がこれを少し明確にすることを願っています。ところで-SOに関する上記の質問には、いくつかの良い、はるかに良い答えがあります。


4
-1-悪いアドバイス。new String(...)アプリケーションが明確なIDを持つ文字列を作成することを要求しない限り、「気軽に」使用してはなりません。
スティーブンC

1
そんなこと知ってる。明確にするために投稿を編集しました。
Andreas Dolk、2010年

0

リテラルプールには、キーワードを使用せずに作成された文字列が含まれていますnew

違いがあります。新しい参照のない文字列は文字列リテラルプールに格納され、新しい文字列はヒープメモリにあると言います。

newを含む文字列は、他のオブジェクトと同じようにメモリ内の別の場所にあります。


0

StringはJavaの不変クラスだからです。

なぜそれが不変なのですか?Stringは不変なので、複数のスレッド間で共有でき、String操作を外部で同期する必要はありません。As Stringは、クラスの読み込みメカニズムでも使用されます。したがって、Stringが変更可能である場合、java.io.writerはabc.xyz.mywriterに変更されている可能性があります。


0
TString obj1 = new TString("Jan Peter");                
TString obj2 = new TString("Jan Peter");                    

if (obj1.Name == obj2.Name)                 
    System.out.println("True");
else                
    System.out.println("False");

出力:

本当

2つの個別のオブジェクトを作成しました。どちらにもフィールド(参照) '名前'があります。したがって、この場合でも、Javaの扱い方を理解していれば、「Jan Peter」が共有されます。


0

StringPoolは、Javaのハッシュマップを使用して実装されています。常に新しいキーワードで作成する場合、文字列プールを検索せず、そのための新しいメモリを作成します。これは、メモリを集中的に使用する操作を実行していて、パフォーマンスに影響を与える新しいキーワードですべての文字列を作成する場合に必要になります。私たちのアプリケーションの。文字列を作成するために新しいキーワードを使用しないことをお勧めします。それは、それだけがHashmapである文字列プールに移動するためです(メモリが節約され、新しいキーワードで作成された文字列がたくさんある場合、ここに格納されます)。文字列が既に存在する場合、その参照(通常はスタックメモリに常駐します)は、新しく作成された文字列に返されます。したがって、パフォーマンスを向上させるために行われました。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.