3

subString()などのメソッドで新しいStringインスタンスの新しいchar配列が作成されないように、JavaStringがその中のchar配列を再利用することに気づきました。この目的のために、Stringにはいくつかの非公開コンストラクターがあり、文字列配列と2つのintを範囲として受け入れてStringインスタンスを構築します。

しかし、今日まで、splitは元のStringインスタンスのchararrも再利用することがわかりました。ここで、ファイルからloooooong行を読み取り、それを「、」で分割し、実際の使用のために非常に制限された列を切り取りました。行のすべての部分がlooooongchar配列の参照を密かに保持しているため、すぐにOOOを取得しました。

ここにサンプルコードがあります:

ArrayList<String> test = new ArrayList<String>(3000000);
BufferedReader origReader = new BufferedReader(new FileReader(new File(
        "G:\\filewithlongline.txt")));
String line = origReader.readLine();
int i = 0;
while ((line = origReader.readLine()) != null) {
    String name = line.split(',')[0];
    test.add(name);
    i++;
    if (i % 100000 == 0) {
        System.out.println(name);
    }
}
System.out.println(test.size());

吐き出されたすべてのStringインスタンスが「浅いコピー」ではなく「実際の深いコピー」であることを確認するためのJDKの標準的な方法はありますか?

現在、非常に醜い回避策を使用して、新しいStringインスタンスを強制的に作成しています。

ArrayList<String> test = new ArrayList<String>(3000000);
BufferedReader origReader = new BufferedReader(new FileReader(new File(
        "G:\\filewithlongline.txt")));
String line = origReader.readLine();
int i = 0;
while ((line = origReader.readLine()) != null) {
    String name = line.split(',')[0]+"  ".trim(); // force creating a String instance
    test.add(name);
    i++;
    if (i % 100000 == 0) {
        System.out.println(name);
    }
}
System.out.println(test.size());
4

2 に答える 2

3

最も簡単なアプローチは、新しい文字列を直接作成することです。これは、それが良い考えであるまれなケースの1つです。

String name = new String(line.split(",")[0]); // note the use of ","

別の方法は、ファイルを自分で解析することです。

do {
    StringBuilder name = new StringBuilder();
    int ch;
    while((ch = origReader.read()) >= 0 && ch != ',' && ch >= ' ') {
       name.append((char) ch);
    }
    test.add(name.toString());
} while(origReader.readLine() != null);
于 2012-09-02T17:45:45.603 に答える
2

Stringこの目的で使用できるコピーコンストラクタがあります。

final String name = new String(line.substring(0, line.indexOf(',')));

...または、Peterが提案したように、。まで読むだけ,です。

final StringBuilder buf = new StringBuilder();
do {
  int ch;
  while ((ch = origReader.read()) >= 0 && ch != ',') {
    buf.append((char) ch);
  }
  test.add(buf.toString());
  buf.setLength(0);
} while (origReader.readLine() != null);
于 2012-09-02T20:41:23.827 に答える