23

これは私がインタビューで受けた質問です。

次のように定義された2つの文字列があります

String s1="Java";
String s2="Java";

私の質問は、これら 2 つの参照が同じメモリ位置を指しているかどうかです。一般に、同一の文字列を (new キーワードを使用せずに) 作成する場合、コンテンツは一度だけメモリに格納され、同じコンテンツを持つすべての String オブジェクトは、文字列「Java」を冗長に格納することなく、同じ場所を参照するだけですか? s1 と s2 のハッシュ コードは同じです。しかし、ハッシュコードはオブジェクトのメモリ位置に直接依存していますか?

4

9 に答える 9

26

The process of combining identical strings is called "interning", and has been done for many years by lots of language compilers, but not always. The answer to the question, especially as expanded by @GennadyVanin--Novosibirsk, depends on the language and the compiler implementation. For Java, all constant strings are interned, as required by the Java Language Specification. But that's only constant string expressions, and only when they're compiled at the same time. If you have two Java strings sufficiently separated in time and space (e.g., compiled into separate JAR files), they will not be the same object. Similarly, dynamically created Java strings (e.g., the output of various toString() methods) won't be interned unless the method specifically requests it via String.intern(). And yes, all uses of an interned string will share the same memory locations - that's a big part of why strings are interned in the first place.

As to other languages, that's a bigger question, but with all the information in these answers, I'm sure you can research it on the web. Suffice it to say that there is no universal agreement on how this ought to be done.

于 2013-04-04T11:14:12.260 に答える
8
String s1="Java";
String s2="Java";
My question is whether these two references point to the same memory location  

Java言語仕様の§3.10.5を引用する愚かな:

文字列リテラルは、クラス String のインスタンスへの参照です ( §4.3.1§4.3.3 )。

さらに、文字列リテラルは常に String クラスの同じインスタンスを参照します。これは、文字列リテラル (より一般的には、定数式の値である文字列 ( §15.28 )) が、メソッド String.intern を使用して一意のインスタンスを共有するために「インターン」されているためです。

そして、そこにあるコード例へのコメントを読んでください:

この例は、次の 6 つのポイントを示しています。

  • 同じパッケージ (§7) 内の同じクラス (§8) 内のリテラル文字列は、同じ String オブジェクト (§4.3.1) への参照を表します。

  • 同じパッケージ内の異なるクラス内のリテラル文字列は、同じ String オブジェクトへの参照を表します。

  • 同様に、異なるパッケージの異なるクラス内のリテラル文字列は、同じ String オブジェクトへの参照を表します。

  • 定数式 (§15.28) によって計算された文字列は、コンパイル時に計算され、リテラルであるかのように扱われます。

  • 実行時に連結によって計算された文字列は新しく作成されるため、区別されます。

  • 計算された文字列を明示的にインターンした結果は、同じ内容の既存のリテラル文字列と同じ文字列になります。

于 2013-04-05T07:56:38.773 に答える
7

コンパイラが文字列リテラルを最適化すると、s1 と s2 の両方が同じ値を持つため、必要な文字列オブジェクトは 1 つだけであることがわかります。Java では文字列は不変なので安全です。

String s1="Java";
String s2="Java";
System.out.println(s1== s2);

と が同じオブジェクトを指しているtrueためs1、これにより結果が得られます。s2

文字列プール は、既に定義されているすべての文字列がいくつかの「プール」に格納され、新しい文字列オブジェクトを作成する前に、コンパイラがそのような文字列が既に定義されているかどうかをチェックするメカニズムです。

于 2013-04-04T08:00:56.937 に答える
3

例。

最初の例

String s1 = "FirstString";
String s2 = "FirstString";

 if(s1 == s2) {
   //This condition matched true because java don't make separate object for these two string. Both strings point to same reference.
 }

2 番目の例

String s1= "FirstString";
String s2 = new String("FirstString");

if(s1.equals(s2)) {
  //This condition true because same content.
}

if(s1 == s2) {
  //This condition will be false because in this java allocate separate reference for both of them
}

結論: Java は文字列が存在するかどうかをチェックします。new を使用して 2 番目の文字列のオブジェクトを作成し、コンテンツが異なる場合は、オブジェクトを作成し、異なる参照を割り当てます。 .

于 2013-04-04T08:02:20.603 に答える
0
String s1="Java";
String s2="Java"; 

それらは同じメモリ位置を指していますか?

私はもともと「いいえ」と言っていましたが、上記の場合は、以下の StringPool の回答を参照してください。実際には「はい」です..

「(新しいキーワードなしで) 同一の文字列を作成する場合、コンテンツは一度だけメモリに格納され、同じコンテンツを持つすべての String オブジェクトは同じ場所を参照するだけですか?」

...質問「Java Strings and StringPool」の詳細な回答を参照してください

「s1 と s2 のハッシュ コードは同じですが、ハッシュ コードはオブジェクトのメモリ位置に直接依存していますか?」

いいえ、ハッシュコードは文字列の内容に依存します

于 2013-04-04T08:02:04.680 に答える
0
String s1="Java";
String s2="Java";

どちらも同じオブジェクトを指しています。詳細については、ここをクリックしてください

于 2013-04-04T08:46:31.530 に答える
0

他に追加: new キーワードは、常に新しいオブジェクトの作成を強制します。以下のように宣言した場合:

String s1 = "some";
String s2 = "some";

次に、文字列プーリング メカニズムを使用して、s1 と s2 の両方の参照が値「some」を持つ同じ文字列オブジェクトを参照します。

于 2013-04-04T08:05:19.923 に答える
0

あなたが持っているとき

String str1 = new String("BlaBla");  //In the heap!
String str2 = new String("BlaBla");  //In the heap!

次に、演算子(およびコンストラクター)を介して明示的にStringオブジェクトを作成しています。newこの場合、各オブジェクトが異なるストレージの場所を指すようになります。

ただし、次の場合:

String str1 = "BlaBla";        
String str2 = "BlaBla";

次に、暗黙の構築を行います。2 つの文字列リテラルは、同じ値を持つ場合、同じストレージを共有します。これは、Java が同じ文字列のストレージを節約するためです! (同じ値を持つ文字列)

于 2013-04-04T08:05:37.197 に答える