使用相同的字符串文字而不是最终变量有什么好处?
我遇到过一个包含多次使用字符串文字“foo”的类。
我想知道的是,使用这种方法而不是将 String 声明为 Final 并用 Final 变量替换所有文字有什么好处和影响(在对象创建、内存使用和速度方面)?
例如(虽然显然不是真正的单词用法):
private static final String FINAL_STRING = "foo";
public void stringPrinter(){
for(int i=0;i<10;i++){
System.out.println(FINAL_STRING);
}
}
对比:
public void stringPrinter(){
for(int i=0;i<10;i++){
System.out.println("foo");
}
}
哪个更可取,为什么(假设字符串值保持不变)?
上面(第二个)示例是否会导致创建 10 个 String 对象,或者 JVM 是否会意识到实际仅使用了一个文字,并创建了一个引用。如果是这样,将 String 声明为 Final 是否有任何优势(如第一个示例中所示)?
如果解释的代码确实用单个引用替换了字符串文字,那么如果相同的文字出现在多个地方,这是否仍然适用:
public void stringPrinter(){
for(int i=0;i<5;i++){
System.out.println("foo"); // first occurence
System.out.println("foo"); // second occurence
}
}
I've come across a class that includes multiple uses of a string literal, "foo".
What I'd like to know, is what are the benefits and impact (in terms of object creation, memory usage and speed) of using this approach instead of declaring the String as final and replacing all the literals with the final variable?
For example (although obviously not a real word usage):
private static final String FINAL_STRING = "foo";
public void stringPrinter(){
for(int i=0;i<10;i++){
System.out.println(FINAL_STRING);
}
}
Versus:
public void stringPrinter(){
for(int i=0;i<10;i++){
System.out.println("foo");
}
}
Which is preferable and why (assuming the string value will remain constant)?
Would the above (second) example result in 10 String objects being created or would the JVM realise that only a single literal is actually used, and create a single reference. If so, is there any advantage for declaring the String as final (as in the first example)?
If the interpreted code does replace the string literal with a single reference, does that still apply if the same literal occurs in more than one place:
public void stringPrinter(){
for(int i=0;i<5;i++){
System.out.println("foo"); // first occurence
System.out.println("foo"); // second occurence
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
它们将完全相同。在这两种情况下,文字都会被保留(任何导致该字符串与所有其他常量/文字共享相同实例的编译时常量表达式),并且智能编译器+运行时应该毫无问题地将两者减少为最优化的示例。
优点更多地体现在可维护性上。如果您想更改文字,则只需更改一个常量,但如果它们内联包含,则需要搜索并更改每个实例。
They will be exactly the same. The literal is interned (any compile time constant expression that results in that string shares the same instance as all other constants/literals) in both cases and a smart compiler+runtime should have no trouble reducing both to the most optimized example.
The advantage comes more in maintainability. If you want to change the literal, you would need only change one occurrence with a constant but you would need to search and change every instance if they were included inline.
来自 JLS
String 类型的编译时常量总是被“实习”,以便使用 String.intern 方法共享唯一实例。
所以,不,只会有一个字符串对象。
正如马克指出的,这严格来说是可维护性问题,而不是性能问题。
From the JLS
Compile-time constants of type String are always "interned" so as to share unique instances, using the method String.intern.
So, no, there's gonna be only one string object.
As Mark notes, this is strictly the question of maintainability and not performance.
优势不在于性能,而在于可维护性和可靠性。
举一个我最近遇到的真实例子。程序员创建了一个函数,该函数采用一个字符串参数来标识事务的类型。然后在程序中他对这种类型进行了字符串比较。就像:
然后他调用这个函数,并向其传递值“Stock”。
您注意到大小写的差异了吗?原来的程序员也没有。事实证明,这是一个相当微妙的错误,需要弄清楚,因为即使查看两个列表,大小写的差异也没有让我感到惊讶。
相反,如果他声明了最终静态,那么
当他第一次尝试传递“Stock”而不是“stock”时,他会收到编译时错误。
在这个例子中更好的是创建一个枚举,但我们假设他实际上必须将字符串写入输出文件或其他文件,因此它必须是一个字符串。
使用final statics至少有x个优点:
(1)如果你拼写错误,你会得到一个编译时错误,而不是一个可能微妙的运行时错误。
(2) 静态可以为值分配一个有意义的名称。哪个更容易理解:
或
(3)当有多个相关值时,您可以将一组最终静态放在程序的顶部,从而告知未来的读者所有可能的值是什么。我曾多次看到函数将一个值与两个或三个文字进行比较。这让我想知道:是否还有其他可能的值,或者就是这个? (通常最好有一个枚举,但那是另一个故事了。)
The advantage is not in performance, but in maintainability and reliability.
Let me take a real example I came across just recently. A programmer created a function that took a String parameter that identified the type of a transaction. Then in the program he did string compares against this type. Like:
Then he called this function, passing it the value "Stock".
Do you notice the difference in capitalization? Neither did the original programmer. It proved to be a fairly subtle bug to figure out, because even looking at both listings, the difference in capitalization didn't strike me.
If instead he had declared a final static, say
Then the first time he tried to pass in "Stock" instead of "stock", he would have gotten a compile-time error.
Better still in this example would have been to make an enum, but let's assume he actually had to write the string to an output file or something so it had to be a string.
Using final statics gives at least x advantages:
(1) If you mis-spell it, you get a compile-time error, rather than a possibly-subtle run-time error.
(2) A static can assign a meaingful name to a value. Which is more comprehensible:
or
(3) When there are multiple related values, you can put a group of final statics together at the top of the program, thus informing future readers what all the possible values are. I've had plenty of times when I've seen a function compare a value against two or three literals. And that leaves me wondering: Are there other possible values, or is this it? (Better still is often to have an enum, but that's another story.)
所有字符串文字都保存在字符串缓存中(这适用于所有类)
使用常量可以使代码更清晰,为字符串提供一些上下文,并使代码更易于维护,特别是如果相同的字符串出现在多个位置。
All String literals are kept in a String cache (this is across all classes)
Using a constant can make the code clearer, give the the string some context and make the code easier to maintain esp if the same string appears in multiple places.
这些字符串文字被内部化,因此在循环中不会创建新的 String 对象。不过,两次使用相同的文字仍然可能是代码异味的标志;但不是在速度或内存使用方面。
Those string literals are internalized, so no new String objects are created in the loop. Using the same literal twice could still be a sign for code smell, though; but not in terms of speed or memory usage.
在您提供的情况下,我认为将其声明为
FINAL_STRING
的最大原因是确保它保留在一个集中位置。该字符串常量只会有一个实例,但第一个示例更容易维护。In the cases you are providing, I believe the biggest reason for having it declared as
FINAL_STRING
somewhere is to ensure it stays in one centralized location. There will only ever be one instance of that string constant, but the first example is far easier to maintain.