私はJavaを初めて使用し、私が信じていることと矛盾するステートメントを読みました。次のコードを検討してください。
String str1 = "dave";
String str2 = "dave";
str1とstr2はどちらも一意の変数ですが、まったく同じ値を参照します。では、メモリ内にいくつの一意のオブジェクトが作成されますか?1または2、そして誰かがその理由を説明できますか?
あなたの例では、文字列がインターンされているため、それらは同じオブジェクトを参照しています。
一般に、newを使用すると新しいオブジェクトが作成されるため、以下を使用します。
String str1 = new String("dave");
String str2 = new String("dave");
ヒープ内に2つの異なるオブジェクトを作成します。
それほど複雑ではありません。文字列について話している場合を除いて;-)
まず、文字列を無視して、次の単純なタイプを想定しましょう。
public class ValueHolder {
private final int value;
public ValueHolder(int value) {
this.value = value;
}
public int getValue() {
return value;
}
}
このような2行がある場合:
ValueHolder vh1 = new ValueHolder(1);
ValueHolder vh2 = new ValueHolder(1);
次に、ヒープ上に正確に2つのオブジェクトを作成します。それらはまったく同じように動作し、まったく同じ値が格納されていますが(変更することはできません)、2つのオブジェクトがあります。
だからvh1 == vh2
戻ってきfalse
ます!
同じことがオブジェクトにも当てはまります。同じ値を持つString
2つのオブジェクトが存在する可能性があります。String
ただし、特定のことが1つあります。コードでリテラル(*)String
を使用すると、Javaはこれより前に発生したものを(インターンと呼ばれるプロセスを介して)再利用しようとします。String
したがって、サンプルコードstr1
でstr2
は、同じオブジェクトを指します。
(*)またはより正確には:型のコンパイル時定数式String
。
Object
同じオブジェクトを指す1つの一意の参照と2つの参照があります。これは、String
プーリング(またはインターン)の結果です。両方のString
リテラルの内容が同じであるとすると、2つの別々 のリテラルを確実に作成できるようにする唯一の方法は、コンストラクターObjects
の1つを明示的に呼び出すことです。String
あなたはこれの速記版を書いています
String str1 = new String("dave");
String str2 = new String("dave");
したがって、str1とstr2は異なるオブジェクトであり、そのように別々に変更できます。
元の文字列である「dave」は、別の参照とともにメモリに1回だけ存在します。
場合によります。小さなテストプログラムを作成する場合、Javaはメモリを節約し、参照を再利用することであなたに有利に働きかけようとしているため、同じ参照が含まれる可能性が非常に高くなります。str2がユーザー入力からのものである場合、2つの異なる参照である可能性があります。テストする良い方法は、比較で==を使用することです。2つが==の場合、それらは同じメモリ位置を参照しています。そうでない場合、それらは2つの異なる参照です。これは、多くの初心者プログラマーを捨てます。なぜなら、彼らが最初にコードを書き始めたとき、彼らは==を使用し、それが機能することを確認し、その後、比較が機能しない理由を理解できないからです。
Javaが「舞台裏」で参照を再利用する時期を具体的に説明することはできませんが、値がいつどのように作成されるかに関係しています。