3

我注意到 Java String 将在其中重用 char 数组,以避免在 subString() 等方法中为新的 String 实例创建新的 char 数组。为此目的,String 中有几个 unpublish 构造函数,接受一个 char 数组和两个 int 作为范围来构造一个 String 实例。

但是直到今天我发现 split 也会重用原始 String 实例的 char arr 。现在我从一个文件中读取了一个 loooooong 行,用“,”分割它,并为实际使用剪切了一个非常有限的列。因为每一行都偷偷持有looooong char数组的引用,所以很快就得到了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());

JDK中是否有任何标准方法来确保吐出的每个String实例都是“真正的深拷贝”而不是“浅拷贝”?

现在我正在使用一个非常丑陋的解决方法来强制创建一个新的 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

最简单的方法是直接创建一个新字符串。这是一个好主意的罕见情况之一。

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(',')));

...或者,正如彼得建议的那样,只阅读直到,.

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 回答