Java中表达"new String(...)"的目的是什么?

Uri*_*Uri 63 java string

在查看在线代码示例时,我有时会通过使用new运算符将String常量赋值给String对象.

例如:

String s;
...
s = new String("Hello World");
Run Code Online (Sandbox Code Playgroud)

当然,这与之相比

s = "Hello World";
Run Code Online (Sandbox Code Playgroud)

我不熟悉这种语法,也不知道目的或效果是什么.由于String常量通常存储在常量池中,然后以JVM处理String常量的任何表示形式存在,甚至还会在堆上分配任何内容?

Law*_*Dol 72

您可能需要的一个地方new String(String)是强制子字符串复制到新的基础字符数组,如

small=new String(huge.substring(10,20))
Run Code Online (Sandbox Code Playgroud)

但是,遗憾的是,这种行为没有记录,并且依赖于实现.

当我将大文件(一些高达20 MiB)读入一个字符串并在事后将其雕刻成行后,我就被这个烧了.我最后得到了引用由整个文件组成的char []的行的所有字符串.不幸的是,无意中保留了对整个数组的引用,因为我所持有的几行比处理文件的时间更长 - 我被迫用new String()它来解决它.

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

small=new String(huge.substring(10,20).toCharArray());
Run Code Online (Sandbox Code Playgroud)

遗憾的是,必须toCharArray()在String构造函数中复制数组两次,一次为一次,一次为一次.

需要有一种记录的方法来通过复制现有字符串来获取新的字符串; 或者String(String)需要改进的文件以使其更加明确(这里有一个含义,但它的解释相当模糊和开放).

假设Doc没有声明的缺陷

为了回应那些不断涌现的评论,请观察Apache Harmony实现的内容new String():

public String(String string) {
    value = string.value;
    offset = string.offset;
    count = string.count;
}
Run Code Online (Sandbox Code Playgroud)

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

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

显着的部分是"参数字符串的副本"; 它没有说"参数字符串的副本和支持字符串的基础字符数组".

请注意您编写文档而不是一个 实现.

  • @R.Bemrose.不,这就是***暗示的.它说的是你将获得*String*对象的新副本 - 它没有声明所述对象的组成内容.共享底层数组的新String仍然是一个新的String和旧的String的副本.与`String(char [] value)`对比,它明确指出:复制字符数组的内容. (7认同)
  • 请注意,在最新版本的Oracle JVM子串中,**不会以本答案中描述的方式共享底层数组**.`substring`反而将数据复制到一个新数组.这开始于Java 1.7 update 6. [见这里](http://stackoverflow.com/a/20275133/452775). (5认同)
  • @Glowcoder - 做出你想要的所有推论,这不是*JavaDoc所说的.而IIRC至少有一个主要的JVM实现实现了`new String(String)`而没有复制底层字符数组 - 它可能是Apache Harmony,但我不确定. (2认同)

Dav*_*Ray 8

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

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

....

synchronized(lock)
{
    // do something
}
Run Code Online (Sandbox Code Playgroud)

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

  • Object lock = new Object()完全相同;-) (9认同)
  • @maaartinus序列化同步监视器有什么意义?实例之间的同步不起作用,所以没有意义.相比之下,我的显示器总是最终的. (2认同)

Vik*_*kas 6

字符串 s1="foo"; 文字将进入 StringPool 并 s1 将引用。

字符串 s2="foo"; 这次它将检查“foo”文字是否已在 StringPool 中可用,是否像现在一样存在,因此 s2 将引用相同的文字。

字符串 s3=new String("foo"); “foo”文字将首先在 StringPool 中创建,然后通过 string arg 构造函数创建 String 对象,即由于通过 new 运算符创建对象而在堆中创建“foo”,然后 s3 将引用它。

字符串 s4=new String("foo"); 与s3相同

所以System.out.println(s1==s2); // true由于字面比较。

System.out.println(s3==s4); //由于对象比较而返回 false(s3 和 s4 在堆中的不同位置创建)

  • 不知道为什么这会被投票...它没有以任何方式回答这个问题。 (5认同)