オリジナル: 「 」またはコンストラクターを使用して Java 文字列を作成しますか? By X Wang Java では、次の 2 つの方法を使用して文字列を作成できます。
String x = "abc";
String y = new String("abc");
二重引用符の使用とコンストラクターの使用の違いは何ですか?
1. 二重引用符と コンストラクタ
この質問は 2 つの簡単な例を見て答えることができます。例 1:String a = "abcd";
String b = "abcd";
System.out.println(a == b); // True
System.out.println(a.equals(b)); // True
a==b
a
これらは両方とも同じオブジェクト、つまりメソッド領域でリテラルとして宣言された文字列 (以下の文字列リテラル) を参照しているため trueb
になります (読者にはリソースのソースを参照してください: Java を理解するためのトップ 8 の図、図 8)。同じ文字列リテラルが複数回作成された場合、文字列のコピーは 1 つだけ、つまりインスタンスが 1 つだけ (この場合は「abcd」) だけがメモリに保存されます。これを「ストリングインターン」といいます。コンパイル時に処理されるすべての文字列定数は、自動的に Java にインターンされます。例 2:
String c = new String("abcd");
String d = new String("abcd");
System.out.println(c == d); // False
System.out.println(c.equals(d)); // True
c==d
false は、メモリ (ヒープ上) 内にある 2 つの異なるオブジェクトを参照しているc
ためです。d
異なるオブジェクトには常に異なる参照があります。この図は、上記の 2 つの状況を示しています。
2. プログラム実行段階でのインターン文字列
著者は LukasEder に感謝します (以下のコメントは彼のものです): コンストラクターを使用して 2 つの文字列が作成された場合でも、プログラムの実行中に文字列インターニングが発生することもあります。String c = new String("abcd").intern();
String d = new String("abcd").intern();
System.out.println(c == d); // Now true
System.out.println(c.equals(d)); // True
3. 二重引用符を使用する場合とコンストラクターを使用する場合
リテラル「abcd」は常に String 型であるため、コンストラクターを使用すると、追加の不要なオブジェクトが作成されます。したがって、文字列を作成するだけの場合は二重引用符を使用する必要があります。実際にヒープ上に新しいオブジェクトを作成する必要がある場合は、コンストラクターを使用する必要があります。ユースケースはここに示されています (オリジナル) 。(以下に翻訳したテキストを示します。ただし、このリンクにあるコメンテーターのコードをよく理解しておくことを強くお勧めします。)JDK 6 および JDK 7 の substring() メソッド
JDK 6 と JDK 7 の substring() メソッドX Wang による JDK 6 と JDK 7 のメソッドsubstring(int beginIndex, int endIndex)
は異なります。これらの違いを理解すると、この方法をより適切に使用できるようになります。読みやすくするために、以下ではsubstring()
完全な構文を意味します。substring(int beginIndex, int endIndex)
。
1. substring() は何をしますか?
このメソッドは、substring(int beginIndex, int endIndex)
文字番号で始まりbeginIndex
文字番号で終わる文字列を返しますendIndex-1
。
String x = "abcdef";
x = x.substring(1,3);
System.out.println(x);
出力:
bc
2. substring() が呼び出されると何が起こりますか?
ご存知かもしれませんが、不変性のためx
、 の結果を x に代入するとx.substring(1,3)
、x
完全に新しい行を指します (図を参照)。 ただし、この図は完全に正しいわけではありません。ヒープ内で実際に何が起こっているかを示すものではありません。が呼び出されたときに実際に起こることは、substring()
JDK 6 と JDK 7 では異なります。
3. JDK 6のsubstring()
文字列型は配列型でサポートされていますchar
。JDK 6 では、クラスにString
3 つのフィールドが含まれます: char value[]
、int offset
、int count
。これらは、実際の文字配列、配列内の最初の文字のインデックス、行内の文字数を格納するために使用されます。メソッドが呼び出されるとsubstring()
、新しい行が作成されますが、変数の値は依然としてヒープ上の同じ配列を指します。2 つの文字列の違いは、文字数と配列内の開始文字のインデックス値です。 以下のコードは簡略化されており、問題を説明するための基本的な部分のみが含まれています。
//JDK 6
String(int offset, int count, char value[]) {
this.value = value;
this.offset = offset;
this.count = count;
}
public String substring(int beginIndex, int endIndex) {
//check boundary
return new String(offset + beginIndex, endIndex - beginIndex, value);
}
4. JDK 6 の substring() によって引き起こされる問題
非常に長い文字列があるが、その一部だけが必要な場合は、 を使用して毎回取得しますsubstring()
。ほんの一部しか必要としないにもかかわらず、文字列全体を保存する必要があるため、実行上の問題が発生します。JDK 6 の場合、解決策は以下のコードであり、文字列を実際の部分文字列にキャストします。
x = x.substring(x, y) + ""
ユーザーSTepeR が質問を作成しました (コメントを参照) が、ポイント 4 を追加する必要があると思われました。「substring()
JDK 6 で発生する問題」は、より広範な例です。これが答えとなり、他の人が問題の内容をすぐに理解するのに役立つことを願っています。コードは次のとおりです。
String a = "aLongLongString";
String b = a.substring(1, 2);
String c = a.substring(2, 6);
そのため、JDK 7 ではb
、с
タイプ a のオブジェクトのメソッドString
を呼び出して作成されたsubstring()
タイプ a のオブジェクトString
は、ヒープ内に新しく作成された 2 つの配列 ( L
for b
、ongL
for )を参照しますc
。これら 2 つの新しい配列は、a によって参照される元の配列とともにヒープに保存されますaLongLongString
。それらの。元の配列はどこにも消えません。ここで JDK 6 に戻りましょう。JDK 6 では、ヒープには 1 つの配列が含まれますaLongLongString
。コード行を実行した後
String b = a.substring(1, 2);
String c = a.substring(2, 6);
オブジェクトは、オブジェクトに対応するヒープ内の同じ配列をb
参照します。- 1 番目のインデックスから 2 番目の要素、- 2 番目のインデックスから 6 番目の要素 (番号付けは 0 から始まります、注意)。それらの。明らかに、JDK 6 で変数または c にさらにアクセスすると、実際には元の配列の必要な要素がヒープに「カウント」されます。JDK 7 では、変数または c にさらにアクセスすると、すでに作成されてヒープ内に「存在している」必要な小さな配列にアクセスすることになります。それらの。このような状況では、明らかに JDK 7 は物理的により多くのメモリを使用します。しかし、考えられるオプションを想像してみましょう。変数の特定の部分文字列が変数 に割り当てられ、将来的には誰もがそれらのみを使用します (オブジェクトと ) 。もう誰も変数 a にアクセスするだけではなく、変数 a への参照も存在しません (これが記事の著者の意味するところです)。その結果、ある時点でガベージ コレクターがトリガーされ、(もちろん最も一般的な形式で) 2 つの異なる状況が発生します: JDK 6 : オブジェクトは破棄されます (ガベージ コレクション) 、ただし - 元の巨大な配列ヒープの中では生きています。常に使用されています。 JDK 7:オブジェクト a は、ヒープ内の元の配列とともに破棄されます。これは、JDK 6 でメモリ リークを引き起こす可能性がある点です。 c
a
b
c
b
b
b
c
a
b
c
a
b
c
5. JDK 7のsubstring()
このメソッドは JDK 7 で改良されました。JDK 7 では、substring()
実際にはヒープ上に新しい配列が作成されます。
//JDK 7
public String(char value[], int offset, int count) {
//check boundary
this.value = Arrays.copyOfRange(value, offset, offset + count);
}
public String substring(int beginIndex, int endIndex) {
//check boundary
int subLen = endIndex - beginIndex;
return new String(value, beginIndex, subLen);
}
GO TO FULL VERSION