Java中expression式“new String(…)”的用途是什么?

在查看在线代码示例时,我有时会通过使用new运算符来发现一个String常量赋值给一个String对象。

例如:

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

这当然比起来

 s = "Hello World"; 

我不熟悉这个语法,不知道这个目的或效果是什么。 由于string常量通常存储在常量池中,然后JVM用于处理string常量的任何表示forms,甚至可以在堆上分配任何东西吗?

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

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

但是,这种行为不幸的是没有文档和执行依赖。

在阅读大文件(一些高达20兆字节)时,我被烧毁成一个string,并在事实之后将其刻成线。 我结束了引用由整个文件组成的char []行的所有string。 不幸的是,无意中保留了一个引用整个数组的行,我把它放在了比处理文件更长的时间 – 我被迫使用new String()来解决它。

唯一的不可知的方式来做到这一点是:

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

这不幸的是必须复制数组两次,一次为toCharArray()和一次在string构造函数。

需要有一个文档化的方式来获得一个新的string,通过复制现有的字符; 或String(String)的文档需要改进,以使其更加明确(这里有一个含义,但它是相当模糊和开放的解释)。

假设文件没有说明的缺陷

为了回应持续出现的意见,观察Apache Harmony实现new String()是什么:

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

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

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

突出部分是“参数string的副本”; 它不会说“参数string的副本和支持string的底层字符数组”。

小心你编程的文档,而不是一个 实现

唯一一次我发现这有用的是在声明lockingvariables:

 private final String lock = new String("Database lock"); .... synchronized(lock) { // do something } 

在这种情况下,像Eclipse这样的debugging工具将在列出当前持有或正在等待的线程locking时显示string。 你必须使用“新的string”,即分配一个新的string对象,否则共享string文字可能被locking在一些其他不相关的代码。

String s1 =“foo”; 文字将进入StringPool和S1将引用。

String s2 =“foo”; 这次它会检查“foo”文字是否已经存在于StringPool中,或者不存在,所以s2会引用相同的文字。

String s3 = new String(“foo”); 首先在StringPool中创build“foo”字面,然后通过stringarg构造函数创buildstring对象,即由于通过new操作符创build对象而在堆中创build“foo”,则s3将引用它。

String s4 = new String(“foo”); 和s3一样

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

System.out.println(s3 == s4); //由于对象比较(s3和s4是在堆中的不同位置创build的)

Software Monkey和Ruggs描述的构造函数的唯一实用程序似乎已经从JDK7中消失了。 类String中不再有offset字段,并且子string始终使用

 Arrays.copyOfRange(char[] original, int from, int to) 

修剪拷贝的字符数组。

那么,这取决于在这个例子中“…”是什么。 如果它是一个StringBuffer,或者一个字节数组,或者什么的,你会得到一个由你传递的数据构造的String。

但是,如果它只是另一个string,就像在new String("Hello World!") ,那么它应该被replace为"Hello World!" , 在所有情况下。 string是不可变的,所以克隆一个没有任何用处 – 创build一个新的String对象只是作为一个现有String的副本(无论它是一个字面量还是另一个stringvariables)。

事实上,有效的Java(我强烈build议)使用这个作为“避免创build不必要的对象”的例子之一:


作为不该做的一个极端例子,考虑一下这个陈述:

 String s = new String("stringette"); **//DON'T DO THIS!** 

(Effective Java,第二版)

一般来说,这表示对初始化时声明的新式C ++风格不熟悉的人。

回到C日,在内部范围内定义自动variables并不被认为是好的forms; C ++消除了parsing器限制,Java扩展了这个限制。

所以你看到的代码

 int q; for(q=0;q<MAX;q++){ String s; int ix; // other stuff s = new String("Hello, there!"); // do something with s } 

在极端的情况下,所有的声明可能在函数的顶部,而不是像在这里的for循环那样在封闭的范围内。

一般来说,这样做的效果是导致一个stringctor被调用一次,并将结果string抛出。 (为了避免这种情况,正是Stroustrup允许在代码中的任何地方声明的原因。)所以,你是正确的,它是最好的,没有必要和不好的风格,可能实际上是不好的。

我想这将取决于你所看到的代码示例。

大部分时间在代码示例中使用类构造函数“new String()”只是为了显示一个非常了解的java类,而不是创build一个新类。

你应该避免大部分时间使用它。 不仅因为string文字被实现,而且主要是因为string不可变。 代表同一个对象的两个副本是没有意义的。

虽然Ruggs的文章是“有趣的”,但除非是非常具体的情况,否则不应该使用它,因为它会造成更多的伤害。 您将编码为实现而不是规范,并且相同的代码无法在JRockit,IBM VM或其他实例中运行。

有两种方法可以在Java中创buildstring。 以下是两种方法的例子:1)声明一个Stringtypes的variables(一个Java类),并将其赋值给一个应该放在双引号之间的值。 这将在内存的string池区域创build一个string。 例如:String str =“JAVA”;

2)使用String类的构造函数,并将一个string(在双引号内)作为parameter passing。 例如:String s = new String(“JAVA”); 这将在主内存中创build一个新的stringJAVA,如果该string尚不存在于string池中,则会在string池中创build一个新的stringJAVA。