Java 中表达式“new String(...)”的目的是什么?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/390703/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
What is the purpose of the expression "new String(...)" in Java?
提问by Uri
While looking at online code samples, I have sometimes come across an assignment of a String constant to a String object via the use of the new operator.
在查看在线代码示例时,我有时会遇到通过使用 new 运算符将 String 常量分配给 String 对象的情况。
For example:
例如:
String s;
...
s = new String("Hello World");
This, of course, compared to
当然,这相比
s = "Hello World";
I'm not familiar with this syntax and have no idea what the purpose or effect would be. Since String constants typically get stored in the constant pool and then in whatever representation the JVM has for dealing with String constants, would anything even be allocated on the heap?
我不熟悉这种语法,也不知道目的或效果是什么。由于字符串常量通常存储在常量池中,然后以 JVM 用于处理字符串常量的任何表示形式存储,是否会在堆上分配任何内容?
回答by Lawrence Dol
The one place where you may thinkyou want new String(String)is to force a distinct copy of the internal character array, as in
您可能认为需要的一个地方new String(String)是强制内部字符数组的不同副本,如
small=new String(huge.substring(10,20))
However, this behavior is unfortunately undocumented and implementation dependent.
然而,不幸的是,这种行为没有记录并且依赖于实现。
I have been burned by this when reading large files (some up to 20 MiB) into a String and carving it into lines after the fact. I ended up with all the strings for the lines referencing the char[] consisting of entire file. Unfortunately, that unintentionally kept a reference to the entire array for the few lines I held on to for a longer time than processing the file - I was forced to use new String()to work around it, since processing 20,000 files very quickly consumed huge amounts of RAM.
在将大文件(一些高达 20 MiB)读取到一个字符串中并在事后将其雕刻成行时,我已经被这个烧毁了。我最终得到了引用由整个文件组成的 char[] 的行的所有字符串。不幸的是,这无意中保留了对整个数组的引用,因为我坚持的几行比处理文件的时间更长 - 我被迫使用new String()它来解决它,因为处理 20,000 个文件很快就消耗了大量的 RAM。
The only implementation agnostic way to do this is:
唯一实现不可知的方法是:
small=new String(huge.substring(10,20).toCharArray());
This unfortunately must copy the array twice, once for toCharArray()and once in the String constructor.
不幸的是,这必须复制数组两次,toCharArray()一次在 String 构造函数中。
There needs to be a documented way to get a new String by copying the chars of an existing one; or the documentation of String(String)needs to be improved to make it more explicit (there is an implication there, but it's rather vague and open to interpretation).
需要有记录的方法来通过复制现有字符串的字符来获取新字符串;或者String(String)需要改进文档以使其更加明确(那里有暗示,但它相当模糊且易于解释)。
Pitfall of Assuming what the Doc Doesn't State
假设文档没有说明的陷阱
In response to the comments, which keep coming in, observe what the Apache Harmony implementation of new String()was:
为了回应不断出现的评论,请观察 Apache Harmony 的实现new String()是什么:
public String(String string) {
value = string.value;
offset = string.offset;
count = string.count;
}
That's right, no copy of the underlying array there. And yet, it still conforms to the (Java 7) String documentation, in that it:
没错,那里没有底层数组的副本。然而,它仍然符合 (Java 7) String 文档,因为它:
Initializes a newly created String object so that it represents the same sequence of characters as the argument; in other words, the newly created string is a copy of the argument string. Unless an explicit copy of original is needed, use of this constructor is unnecessary since Strings are immutable.
初始化新创建的 String 对象,使其表示与参数相同的字符序列;换句话说,新创建的字符串是参数字符串的副本。除非需要原始的显式副本,否则不需要使用此构造函数,因为字符串是不可变的。
The salient piece being "copy of the argument string"; it does not say "copy of the argument string and the underlying character array supporting the string".
突出部分是“参数字符串的副本”;它没有说“参数字符串的副本和支持该字符串的底层字符数组”。
Be careful that you program to the documentationand not oneimplementation.
请注意您对文档而不是一种实现进行编程。
回答by Dave Ray
The only time I have found this useful is in declaring lock variables:
我发现这很有用的唯一一次是在声明锁变量时:
private final String lock = new String("Database lock");
....
synchronized(lock)
{
// do something
}
In this case, debugging tools like Eclipse will show the string when listing what locks a thread currently holds or is waiting for. You have to use "new String", i.e. allocate a new String object, because otherwise a shared string literal could possibly be locked in some other unrelated code.
在这种情况下,Eclipse 之类的调试工具会在列出线程当前持有或正在等待的锁时显示字符串。您必须使用“新字符串”,即分配一个新的字符串对象,否则共享字符串文字可能会被锁定在其他一些不相关的代码中。
回答by MasterKiller
The sole utility for this constructor described by Software Monkey and Ruggs seems to have disappeared from JDK7.
There is no longer an offsetfield in class String, and substring always use
Software Monkey 和 Ruggs 描述的这个构造函数的唯一实用程序似乎已经从 JDK7 中消失了。offset类String中不再有字段,子串一直使用
Arrays.copyOfRange(char[] original, int from, int to)
to trim the char array for the copy.
修剪副本的字符数组。
回答by Vikas
String s1="foo";literal will go in StringPool and s1 will refer.
字符串 s1="foo"; 文字将进入 StringPool 并且 s1 将引用。
String s2="foo";this time it will check "foo" literal is already available in StringPool or not as now it exist so s2 will refer the same literal.
字符串 s2="foo"; 这次它将检查“foo”文字是否已经在 StringPool 中可用,因为它现在存在,因此 s2 将引用相同的文字。
String s3=new String("foo");"foo" literal will be created in StringPool first then through string arg constructor String Object will be created i.e "foo" in the heap due to object creation through new operator then s3 will refer it.
String s3=new String("foo"); “foo”文字将首先在 StringPool 中创建,然后通过字符串 arg 构造函数创建字符串对象,即由于通过 new 运算符创建对象而在堆中创建“foo”,然后 s3 将引用它。
String s4=new String("foo");same as s3
String s4=new String("foo"); 与 s3 相同
so System.out.println(s1==s2);//truedue to literal comparison.
所以System.out.println(s1==s2); //由于字面比较为真。
and System.out.println(s3==s4);// falsedue to object comparison(s3 and s4 is created at different places in heap)
和System.out.println(s3==s4); // false由于对象比较(s3 和 s4 在堆的不同位置创建)
回答by Vineet
Well, that depends on what the "..." is in the example. If it's a StringBuffer, for example, or a byte array, or something, you'll get a String constructed from the data you're passing.
嗯,这取决于示例中的“...”是什么。例如,如果它是一个 StringBuffer,或者一个字节数组,或者其他东西,你会得到一个由你传递的数据构造的 String。
But if it's just another String, as in new String("Hello World!"), then it should be replaced by simply "Hello World!", in all cases. Strings are immutable, so cloning one serves no purpose -- it's just more verbose and less efficient to create a new String object just to serve as a duplicate of an existing String (whether it be a literal or another String variable you already have).
但是,如果它只是另一个字符串,例如new String("Hello World!"),则"Hello World!"在所有情况下都应该简单地替换为。字符串是不可变的,所以克隆一个没有任何意义——创建一个新的 String 对象只是为了作为现有 String 的副本(无论它是一个文字还是另一个你已经拥有的 String 变量),这会更加冗长且效率更低。
In fact, Effective Java (which I highly recommend) uses exactly this as one of its examples of "Avoid creating unnecessary objects":
事实上,Effective Java(我强烈推荐)正是使用它作为“避免创建不必要的对象”的示例之一:
As an extreme example of what not to do, consider this statement:
作为不该做什么的极端示例,请考虑以下语句:
String s = new String("stringette"); **//DON'T DO THIS!**
(Effective Java, Second Edition)
(有效的 Java,第二版)
回答by Charlie Martin
Generally, this indicates someone who isn't comfortable with the new-fashioned C++ style of declaring when initialized.
通常,这表明有人对初始化时声明的新式 C++ 风格不满意。
Back in the C days, it wasn't considered good form to define auto variables in an inner scope; C++ eliminated the parser restriction, and Java extended that.
在 C 时代,在内部范围内定义自动变量被认为不是一种好的形式;C++ 消除了解析器的限制,而 Java 对此进行了扩展。
So you see code that has
所以你看到的代码有
int q;
for(q=0;q<MAX;q++){
String s;
int ix;
// other stuff
s = new String("Hello, there!");
// do something with s
}
In the extreme case, all the declarations may be at the top of a function, and not in enclosed scopes like the forloop here.
在极端情况下,所有声明可能都在函数的顶部,而不是像for这里的循环那样在封闭的范围内。
IN general, though, the effect of this is to cause a String ctor to be called once, and the resulting String thrown away. (The desire to avoid this is just what led Stroustrup to allow declarations anywhere in the code.) So you are correct that it's unnecessary and bad style at best, and possibly actually bad.
但是,一般来说,这样做的效果是导致 String ctor 被调用一次,结果 String 被丢弃。(避免这种情况的愿望正是导致 Stroustrup 允许在代码中的任何位置声明的原因。)所以你是对的,它充其量是不必要的和糟糕的风格,而且可能实际上是糟糕的。
回答by user2353653
There are two ways in which Strings can be created in Java. Following are the examples for both the ways: 1) Declare a variable of type String(a class in Java) and assign it to a value which should be put between double quotes. This will create a string in the string pool area of memory. eg: String str = "JAVA";
在 Java 中有两种方法可以创建字符串。以下是这两种方式的示例: 1) 声明一个 String 类型的变量(Java 中的一个类)并将其分配给一个应该放在双引号之间的值。这将在内存的字符串池区域中创建一个字符串。例如:String str = "JAVA";
2)Use the constructor of String class and pass a string(within double quotes) as an argument. eg: String s = new String("JAVA"); This will create a new string JAVA in the main memory and also in the string pool if this string is not already present in string pool.
2)使用String类的构造函数,传入一个字符串(在双引号内)作为参数。例如:String s = new String("JAVA"); 这将在主内存和字符串池中创建一个新字符串 JAVA,如果该字符串尚未出现在字符串池中。
回答by OscarRyz
I guess it will depend on the code samples you're seeing.
我想这将取决于您看到的代码示例。
Most of the times using the class constructor "new String()" in code sample are only to show a very well know java class instead of creating a new one.
大多数情况下,在代码示例中使用类构造函数“new String()”只是为了展示一个非常熟悉的 java 类,而不是创建一个新的类。
You should avoid using it most of the times. Not only because string literals are interned but mainly because string are inmutable. It doesn't make sense have two copies that represent the same object.
大多数时候你应该避免使用它。不仅因为字符串字面量是固定的,而且主要是因为字符串是不可变的。有两个副本代表同一个对象是没有意义的。
While the article mensioned by Ruggs is "interesting"it should not be used unless very specific circumstances, because it could create more damage than good. You'll be coding to an implementation rather than an specification and the same code could not run the same for instance in JRockit, IBM VM, or other.
虽然 Ruggs 提到的文章“有趣”,但除非在非常特殊的情况下否则不应使用它,因为它可能造成的损害大于好处。您将编码实现而不是规范,并且相同的代码不能在 JRockit、IBM VM 或其他中运行。

