Java中表达式“new String(...)”的目的是什么?

2022-08-31 13:21:33

在查看联机代码示例时,我有时会遇到通过使用 new 运算符将 String 常量赋值到 String 对象的情况。

例如:

String s;
...
s = new String("Hello World");

当然,这与

s = "Hello World";

我不熟悉这种语法,也不知道其目的或效果如何。由于字符串常量通常存储在常量池中,然后存储在JVM用于处理字符串常量的任何表示形式中,那么是否会在堆上分配任何内容?


答案 1

您可能认为自己想要的一个地方是强制内部字符数组的独特副本,如new String(String)

small=new String(huge.substring(10,20))

但是,不幸的是,此行为是未记录的,并且依赖于实现。

当我将大文件(有些高达20 MiB)读取到字符串中并在事后将其雕刻成行时,我被此刻录了。我最终得到了引用char[]的行的所有字符串,这些字符由整个文件组成。不幸的是,这无意中保留了对整个数组的引用,因为我保留的几行比处理文件的时间更长 - 我被迫使用它来解决这个问题,因为处理20,000个文件非常快地消耗了大量的RAM。new String()

实现不可知的唯一方法是:

small=new String(huge.substring(10,20).toCharArray());

不幸的是,这必须复制数组两次,一次用于 String 构造函数,一次在 String 构造函数中复制。toCharArray()

需要有一种记录的方法通过复制现有字符串的字符来获得新的字符串;或者需要改进的文档以使其更加明确(那里有一个含义,但它相当模糊且可以解释)。String(String)

假设文档未说明的内容的陷阱

为了回应不断出现的评论,观察Apache Harmony的实现是什么:new String()

public String(String string) {
    value = string.value;
    offset = string.offset;
    count = string.count;
}

没错,那里没有底层数组的副本。然而,它仍然符合(Java 7)字符串文档,因为它:

初始化新创建的 String 对象,使其表示与参数相同的字符序列;换句话说,新创建的字符串是参数字符串的副本。除非需要原始的显式副本,否则不需要使用此构造函数,因为字符串是不可变的。

突出部分是“参数字符串的副本”;它没有说“参数字符串和支持字符串的基础字符数组的副本”。

请注意,您编程到文档而不是一个实现


答案 2

我发现这一点唯一有用的是声明锁变量:

private final String lock = new String("Database lock");

....

synchronized(lock)
{
    // do something
}

在这种情况下,像Eclipse这样的调试工具将在列出线程当前持有或正在等待的锁定内容时显示字符串。您必须使用“new String”,即分配一个新的 String 对象,因为否则共享字符串文本可能会被锁定在其他一些不相关的代码中。