9

String s = "Hello World".substring(0, 5)もしそうなら、新しい文字列を手に入れるだけだといつも思っていましたs = "Hello"。これは、Java API ドキュメントにも記載されています: "Returns a new string that is a substring of this string"

しかし、次の 2 つのリンクを見て、疑い始めました。

Javaでの「new String(...)」という式の目的は何ですか?

役に立たないと思っていた文字列コンストラクタが、結局役に立つことが判明

基本的に、 を使用するとString s = "Hello World".subString(0, 5)、「Hello World」の char 配列を保持する文字列が得られると言われています。

なんで?Java は本当にこのように部分文字列を実装していますか? なぜこのように?まったく新しい短い部分文字列を返さないのはなぜですか?

4

6 に答える 6

5

振り返ってみると、char[]必要がないのに、なぜ new を割り当てるのでしょうか? Stringは不変であるため、これは有効な実装です。アグリゲートの割り当てとメモリを節約します。

于 2012-05-31T08:34:05.540 に答える
4

効率化のための措置だそうです。つまり、部分文字列を取得する場合、新しい char 配列を作成するのではなく、既存の char 配列にウィンドウを作成するだけです。

これは価値がありますか?多分。欠点は、混乱を招くことです (例: this SO questionを参照)。さらに、各Stringオブジェクトは、使用されていない場合でも、オフセット情報を配列に保持する必要があります。

編集:この動作はJava 7の時点で変更されました。詳細については、リンクされた回答を参照してください

于 2012-05-31T08:35:51.683 に答える
1

以前は、Stringcreated withsubString()が同じバッキングを持っていたのは事実でしたが (おそらく、コピーのスペースと時間を節約するため)、Java 7 Update 6 以降、この共有にはメモリのオーバーヘッドがあったchar[]ため、そうではなくなりました。char[]このオーバーヘッドは、(大きな) 文字列が読み込まれ、小さな部分文字列が取得され、大きな文字列が破棄される場合に特に存在します。小さな文字列が長時間保持されると、不要なメモリ使用量が大幅に増加する可能性があります。

いずれにせよ、現在のバージョン (Java 7 Update 21) では、元の文字列のコンストラクターをsubString()呼び出し、コンストラクターは char 配列から指定された範囲のコピーを作成します。String(char value[], int offset, int count)char[]

public String(char value[], int offset, int count) {
    if (offset < 0) {
        throw new StringIndexOutOfBoundsException(offset);
    }
    if (count < 0) {
        throw new StringIndexOutOfBoundsException(count);
    }
    // Note: offset or count might be near -1>>>1.
    if (offset > value.length - count) {
        throw new StringIndexOutOfBoundsException(offset + count);
    }
    this.value = Arrays.copyOfRange(value, offset, offset+count);
}
于 2013-05-13T18:32:15.510 に答える
1

Javaは本当にこのようにsubStringを実装していますか

コード (JDK 7) (単純化したもの) を見ると、はい:

public String substring(int beginIndex, int endIndex) {
    .......
    return new String(offset + beginIndex, endIndex - beginIndex, value);
}

// Package private constructor which shares value array for speed.
String(int offset, int count, char value[]) {
    this.value = value;
    this.offset = offset;
    this.count = count;
}

なぜこのように?まったく新しい短い部分文字列を返さないのはなぜですか?

コメントは、速度が理由であることを暗示しているようです

于 2012-05-31T08:45:29.407 に答える
0

String はとにかく不変だからです。したがって、まったく新しいオブジェクトを作成することはあまり意味がありません

于 2012-05-31T08:35:04.193 に答える
0

文字列は不変であり、メモリを占有することを念頭に置いて、それぞれが新しい文字列を作成する場合、文字列に対していくつかの部分文字列操作を行うことを想定してください! 代わりに、同じ不変文字列を指すが異なるオフセットとカウント プロパティを持つ新しい String オブジェクトを作成するだけです。これで、元の文字列またはその文字列の部分文字列に対していくつの部分文字列を実行しても、メモリ内には文字列自体のコピーが 1 つしかありません。はるかに効率的です。

また、String s = "Hello, World".substring(0,5);操作の順序を考えてください。最初に文字列 "Hello, World" がヒープ上に作成され、新しい String オブジェクトがそれを指します。次に、substring メソッドが新しい String オブジェクトで呼び出され、別の新しい String オブジェクトが作成され、sインスタンスによってポイントされます。したがって、sヒープ「Hello, World」の文字列を指し、offset0 とcount5 を持ちます。

于 2013-05-13T17:56:23.723 に答える