我将假设在下面的每个示例中,您每次都在一个新的 JVM 中加载并执行一次代码。(我还将假设您的代码中没有其他地方使用文字"Java"
......因为这会使事情复杂化。)
1)说如果字符串常量池中没有字符串,如果我说,
String s = "Java";
那么会创建多少个对象呢?
加载方法时会创建一个字符串并将其添加到池中。
2) 现在游泳池里什么也没有,我说,
String s = new String("Java");
现在将创建多少个对象。
加载方法时会创建一个字符串并将其添加到池中。
运行代码时会创建第二个字符串new
,并且不会将其添加到池中。
3) 现在游泳池里什么也没有,我说,
String s = new String("Java");
s.intern();
实习生方法会做什么?
加载方法时会创建一个字符串并将其添加到池中。
第二个字符串由创建new
,它不会添加到池中。
该intern
调用返回第一个字符串。(你不保留参考...)
4) 现在游泳池里什么也没有,我说,
String s = new String("Java");
String s1 = s.intern();
现在会发生什么?
与示例 3 相同。因此,s1
将持有对String
表示"Java"
字符串文字的对象的引用。
我在 SCJP5 Kathy Sierra 的书中读到,当您使用 创建 String 时new
,会创建 2 个对象,一个在堆上,一个在池中。
我怀疑这本书是否准确地说。(你在解释,我认为你的解释有些不准确。)
但是,您的解释大致正确,尽管(这很重要!)表示文字的字符串对象是在加载代码片段时创建并添加到池中的1,而不是在执行时。
为了解决另一个混淆点:
“我的真正意思是,从你给出的答案来看,似乎总是会在字符串常量池中添加一个字符串。”
这是不正确的。这是一个错误的概括。
虽然上述所有 4 种情况都适用,但其他情况则不适用。这取决于原始字符串的来源。在典型的应用程序中,大多数文本数据都是从文件、套接字或用户界面中读取的。发生这种情况时,字符串是从字符数组直接或通过库调用创建的。
这是一个简单(但不切实际)的示例,显示了从其组成字符创建字符串。
String s = new String(new char[]{'J', 'a', 'v', 'a'});
在上面的代码片段中,只创建了一个字符串,它不在字符串池中。如果您希望生成的字符串位于字符串池中,则需要显式调用intern
如下内容:
String s = new String(new char[]{'J', 'a', 'v', 'a'});
s = s.intern();
...这将(如有必要)在字符串池2中创建第二个字符串。
1 - 显然,在某些 JVM 中,字符串文字的创建和实习是延迟完成的,因此无法 100% 确定何时实际发生。但是,它只会发生一次(每个引用文字的类),无论 JVM 执行多少次代码片段。
2 - 没有办法将new
一个字符串放入字符串池中。这实际上违反了 JLS。JLS将new
操作指定为始终创建新对象。