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。