Java 字符串:"String s = new String("silly");"
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/334518/
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
Java Strings: "String s = new String("silly");"
提问by JavaNewbie
I'm a C++ guy learning Java. I'm reading Effective Java and something confused me. It says never to write code like this:
我是一个学习 Java 的 C++ 人。我正在阅读 Effective Java,有些东西让我感到困惑。它说永远不要写这样的代码:
String s = new String("silly");
Because it creates unnecessary String
objects. But instead it should be written like this:
因为它创建了不必要的String
对象。但它应该这样写:
String s = "No longer silly";
Ok fine so far...However, given this class:
到目前为止还好......但是,考虑到这个类:
public final class CaseInsensitiveString {
private String s;
public CaseInsensitiveString(String s) {
if (s == null) {
throw new NullPointerException();
}
this.s = s;
}
:
:
}
CaseInsensitiveString cis = new CaseInsensitiveString("Polish");
String s = "polish";
Why is the first statement ok? Shouldn't it be
CaseInsensitiveString cis = "Polish";
How do I make
CaseInsensitiveString
behave likeString
so the above statement is OK (with and without extendingString
)? What is it about String that makes it OK to just be able to pass it a literal like that? From my understanding there is no "copy constructor" concept in Java?
为什么第一个语句没问题?不应该是
CaseInsensitiveString cis = "Polish";
我如何使
CaseInsensitiveString
行为像String
上面的语句一样正常(有和没有扩展String
)?String 是什么让它可以像这样传递一个文字?根据我的理解,Java 中没有“复制构造函数”的概念?
回答by Alnitak
String
s are special in Java - they're immutable, and string constants are automatically turned into String
objects.
String
s 在 Java 中很特殊——它们是不可变的,并且字符串常量会自动变成String
对象。
There's no way for your SomeStringClass cis = "value"
example to apply to any other class.
您的SomeStringClass cis = "value"
示例无法应用于任何其他课程。
Nor can you extend String
, because it's declared as final
, meaning no sub-classing is allowed.
您也不能扩展String
,因为它被声明为final
,这意味着不允许子类化。
回答by Dan Vinton
You can't. Things in double-quotes in Java are specially recognised by the compiler as Strings, and unfortunately you can't override this (or extend java.lang.String
- it's declared final
).
你不能。Java中双引号中的东西被编译器特别识别为字符串,不幸的是你不能覆盖它(或扩展java.lang.String
- 它已声明final
)。
回答by Adam Rosenfield
String
is a special built-in class of the language. It is for the String
class onlyin which you should avoid saying
String
是该语言的特殊内置类。它仅适用于您应该避免说的String
课程
String s = new String("Polish");
Because the literal "Polish"
is already of type String
, and you're creating an extra unnecessary object. For any other class, saying
因为文字"Polish"
已经是 type String
,并且您正在创建一个额外的不必要的对象。对于任何其他类,说
CaseInsensitiveString cis = new CaseInsensitiveString("Polish");
is the correct (and only, in this case) thing to do.
是正确的(在这种情况下也是唯一的)。
回答by Herms
CaseInsensitiveString and String are different objects. You can't do:
CaseInsensitiveString 和 String 是不同的对象。你不能这样做:
CaseInsensitiveString cis = "Polish";
because "Polish" is a String, not a CaseInsensitiveString. If String extended CaseInsensitiveString String then you'd be OK, but obviously it doesn't.
因为“波兰语”是一个字符串,而不是一个 CaseInsensitiveString。如果 String 扩展了 CaseInsensitiveString String 那么你就可以了,但显然不是。
And don't worry about the construction here, you won't be making unecessary objects. If you look at the code of the constructor, all it's doing is storing a reference to the string you passed in. Nothing extra is being created.
不要担心这里的构造,你不会制造不必要的物体。如果您查看构造函数的代码,它所做的只是存储对您传入的字符串的引用。没有创建任何额外内容。
In the String s = new String("foobar") case it's doing something different. You are first creating the literal string "foobar", then creating a copy of it by constructing a new string out of it. There's no need to create that copy.
在 String s = new String("foobar") 的情况下,它正在做一些不同的事情。您首先创建文字字符串“foobar”,然后通过从中构造一个新字符串来创建它的副本。无需创建该副本。
回答by Darron
In Java the syntax "text" creates an instance of class java.lang.String. The assignment:
在 Java 中,语法“text”创建类 java.lang.String 的一个实例。那作业:
String foo = "text";
is a simple assignment, with no copy constructor necessary.
是一个简单的赋值,不需要复制构造函数。
MyString bar = "text";
Is illegal whatever you do because the MyString class isn't either java.lang.String or a superclass of java.lang.String.
无论你做什么都是非法的,因为 MyString 类既不是 java.lang.String 也不是 java.lang.String 的超类。
回答by Lucas Gabriel Sánchez
First, you can't make a class that extends from String, because String is a final class. And java manage Strings differently from other classes so only with String you can do
首先,你不能创建一个从 String 扩展的类,因为 String 是一个 final 类。并且 java 以不同于其他类的方式管理字符串,因此您只能使用 String
String s = "Polish";
But whit your class you have to invoke the constructor. So, that code is fine.
但是对于您的类,您必须调用构造函数。所以,那个代码没问题。
回答by Leigh
I believe the main benefit of using the literal form (ie, "foo" rather than new String("foo")) is that all String literals are 'interned' by the VM. In other words it is added to a pool such that any other code that creates the same string will use the pooled String rather than creating a new instance.
我相信使用文字形式(即“foo”而不是 new String("foo"))的主要好处是所有字符串文字都被 VM 'interned'。换句话说,它被添加到一个池中,这样创建相同字符串的任何其他代码都将使用池化的字符串,而不是创建一个新实例。
To illustrate, the following code will print true for the first line, but false for the second:
为了说明这一点,以下代码将为第一行打印 true,但为第二行打印 false:
System.out.println("foo" == "foo");
System.out.println(new String("bar") == new String("bar"));
回答by James
In your first example, you are creating a String, "silly" and then passing it as a parameter to another String's copy constructor, which makes a second String which is identical to the first. Since Java Strings are immutable (something that frequently stings people who are used to C strings), this is a needless waste of resources. You should instead use the second example because it skips several needless steps.
在您的第一个示例中,您正在创建一个“愚蠢的”字符串,然后将其作为参数传递给另一个字符串的复制构造函数,这将生成与第一个相同的第二个字符串。由于 Java 字符串是不可变的(经常会刺痛习惯 C 字符串的人),因此这是一种不必要的资源浪费。您应该改用第二个示例,因为它跳过了几个不必要的步骤。
However, the String literal is not a CaseInsensitiveString so there you cannot do what you want in your last example. Furthermore, there is no way to overload a casting operator like you can in C++ so there is literally no way to do what you want. You must instead pass it in as a parameter to your class's constructor. Of course, I'd probably just use String.toLowerCase() and be done with it.
但是,字符串文字不是 CaseInsensitiveString,因此您无法在上一个示例中执行所需的操作。此外,无法像在 C++ 中那样重载强制转换运算符,因此实际上无法做您想做的事。您必须将其作为参数传递给类的构造函数。当然,我可能只是使用 String.toLowerCase() 并完成它。
Also, your CaseInsensitiveString should implement the CharSequence interface as well as probably the Serializable and Comparable interfaces. Of course, if you implement Comparable, you should override equals() and hashCode() as well.
此外,您的 CaseInsensitiveString 应该实现 CharSequence 接口以及可能的 Serializable 和 Comparable 接口。当然,如果你实现了 Comparable,你也应该覆盖 equals() 和 hashCode()。
回答by Steve B.
Strings are treated a bit specially in java, they're immutable so it's safe for them to be handled by reference counting.
字符串在 java 中被特殊对待,它们是不可变的,因此通过引用计数处理它们是安全的。
If you write
如果你写
String s = "Polish";
String t = "Polish";
then s and t actually refer to the same object, and s==t will return true, for "==" for objects read "is the same object" (or can, anyway, I"m not sure if this is part of the actual language spec or simply a detail of the compiler implementation-so maybe it's not safe to rely on this) .
然后 s 和 t 实际上指的是同一个对象,而 s==t 将返回真,因为“==”对于读取的对象“是同一个对象”(或者可以,无论如何,我不确定这是否是实际的语言规范或只是编译器实现的一个细节 - 所以依赖这个可能不安全)。
If you write
如果你写
String s = new String("Polish");
String t = new String("Polish");
then s!=t (because you've explicitly created a new string) although s.equals(t) will return true (because string adds this behavior to equals).
然后 s!=t (因为您已经明确地创建了一个新字符串)尽管 s.equals(t) 将返回 true (因为字符串将此行为添加到 equals 中)。
The thing you want to write,
你想写的东西,
CaseInsensitiveString cis = "Polish";
can't work because you're thinking that the quotations are some sort of short-circuit constructor for your object, when in fact this only works for plain old java.lang.Strings.
无法工作,因为您认为引号是对象的某种短路构造函数,而实际上这只适用于普通的旧 java.lang.Strings。
回答by Ewan Makepeace
In most versions of the JDK the two versions will be the same:
在大多数 JDK 版本中,这两个版本是相同的:
String s = new String("silly");
String s = new String("傻");
String s = "No longer silly";
String s = "不再傻了";
Because strings are immutable the compiler maintains a list of string constants and if you try to make a new one will first check to see if the string is already defined. If it is then a reference to the existing immutable string is returned.
因为字符串是不可变的,编译器会维护一个字符串常量列表,如果您尝试创建一个新的常量,将首先检查该字符串是否已经定义。如果是,则返回对现有不可变字符串的引用。
To clarify - when you say "String s = " you are defining a new variable which takes up space on the stack - then whether you say "No longer silly" or new String("silly") exactly the same thing happens - a new constant string is compiled into your application and the reference points to that.
澄清一下 - 当您说“String s =”时,您正在定义一个占用堆栈空间的新变量-那么无论您说“不再愚蠢”还是 new String("silly") 都会发生完全相同的事情-一个新的常量字符串被编译到您的应用程序中,并且引用指向它。
I dont see the distinction here. However for your own class, which is not immutable, this behaviour is irrelevant and you must call your constructor.
我没有看到这里的区别。然而,对于你自己的类,它不是一成不变的,这种行为是无关紧要的,你必须调用你的构造函数。
UPDATE: I was wrong! Based on a down vote and comment attached I tested this and realise that my understanding is wrong - new String("Silly") does indeed create a new string rather than reuse the existing one. I am unclear why this would be (what is the benefit?) but code speaks louder than words!
更新:我错了!根据附上的反对票和评论,我对此进行了测试,并意识到我的理解是错误的 - new String("Silly") 确实创建了一个新字符串,而不是重用现有字符串。我不清楚为什么会这样(有什么好处?)但代码胜于雄辩!