首页 > 解决方案 > 需要了解的字符串、字符串常量池和字符串实习生方法

问题描述

  1. 假设字符串常量池中没有字符串,如果我说,

    String s = "Java";
    

    那么会创建多少个对象呢?

  2. 现在游泳池里什么也没有,我说,

    String s = new String("Java");
    

    现在,将创建多少个对象?

  3. 现在游泳池里什么也没有,我说,

    String s = new String("Java");
    s.intern();
    

    实习生方法会做什么?

  4. 现在游泳池里什么也没有,我说,

    String s = new String("Java");
    String s1 = s.intern();
    

    现在会发生什么?

请回答,因为我真的很困惑。

正如我在 SCJP5 Kathy Sierra 书中所读到的,当您使用 new 创建一个 String 时,会创建 2 个对象,一个在堆上,一个在池中。

标签: javastringstring-interningstring-pool

解决方案


我将假设在下面的每个示例中,您每次都在一个新的 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操作指定为始终创建新对象。


推荐阅读