8

可能重复:
使用 new 方法创建字符串对象及其与 intern 方法的比较

我正在玩 Strings 以更多地了解它们,我注意到一些我无法解释的东西:

String str1 = "whatever";
String str2 = str1;
String str3 = "whatever";
System.out.println(str1==str2); //prints true...that's normal, they point to the same object
System.out.println(str1==str3); //gives true..how's that possible ?

最后一行如何给出 true ?这意味着 str1 和 str3 在内存中具有相同的地址。

这是一个足够聪明的编译器优化,可以检测到两个字符串文字是相同的(“whatever”),因此将 str1 和 str3 分配给同一个对象?还是我在字符串的底层机制中遗漏了一些东西?

4

4 回答 4

8

因为 Java 有一个唯一的实习实例池,并且字符串字面量存储在这个池中。这意味着第一个“whatever”字符串文字与第三个“whatever”文字完全相同的 String 对象。

正如文件所说:

public String intern()

返回字符串对象的规范表示。一个字符串池,最初是空的,由 String 类私下维护。

当调用 intern 方法时,如果池中已经包含一个等于该 String 对象的字符串,由 equals(Object) 方法确定,则返回池中的字符串。否则,将此 String 对象添加到池中并返回对该 String 对象的引用。

由此可见,对于任何两个字符串 s 和 t,当且仅当 s.equals(t) 为真时,s.intern() == t.intern() 才为真。

所有文字字符串和字符串值的常量表达式都是实习的。字符串文字在 Java 语言规范的 §3.10.5 中定义

返回: 与此字符串具有相同内容的字符串,但保证来自唯一字符串池。


于 2012-11-19T08:59:32.037 回答
6

http://www.xyzws.com/Javafaq/what-is-string-literal-pool/3

正如帖子所说:

与所有对象分配一样,字符串分配在时间和内存方面都被证明是昂贵的。JVM 在实例化字符串文字时会执行一些技巧以提高性能并减少内存开销。为了减少在 JVM 中创建的 String 对象的数量,String 类保留了一个字符串池。每次您的代码创建字符串文字时,JVM 首先检查字符串文字池。如果该字符串已存在于池中,则返回对池实例的引用。如果池中不存在字符串,则实例化一个新的 String 对象,然后将其放入池中。

于 2012-11-19T09:00:13.463 回答
2

如果你这样做:

String str1 = new String("BlaBla");  //In the heap!
String str2 = new String("BlaBla");  //In the heap!

那么您将通过运算符(和构造函数)显式创建一个String对象。new在这种情况下,您将让每个对象指向不同的存储位置。

但如果你这样做:

String str1 = "BlaBla";        
String str2 = "BlaBla";

那么你就有了隐式构造。如果两个字符串字面量具有相同的值,则它们共享相同的存储空间,这是因为 Java 保留了相同字符串的存储空间!(具有相同值的字符串)

于 2012-11-19T09:03:40.093 回答
1

javac编译器组合了给定类文件中相同的字符串文字。

但是在运行时,字符串文字使用与String.intern()相同的方法组合,这意味着即使是不同应用程序中不同类中的字符串(在使用相同对象的同一 JVM 中)。

于 2012-11-19T09:03:08.703 回答