需要了解的String、String常量池和String intern方法

Need to know about String, String Constant pool and String intern method

  1. 说如果String常量池里没有字符串,如果我说,

    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 个对象,一个在堆上,一个在池中。

  1. Then how many objects will be created?

池中有一个String

  1. Now how many objects will be created?

将创建一个String,池中还有一个String

  1. What will the intern method do?

它将尝试将一个 "Java" 放入池中,然后在其中找到另一个 "Java",return 是对步骤 1 中那个 "Java" 的引用。

  1. What will happen now?

第 1 步中的 "Java" 将返回,s1 现在引用它。

  1. Say if there are no strings in the String constant pool, and if i say,

    String s = "Java";

Then how many objects will be created ?

在实习生池中创建了一个字符串对象。 s 由该引用分配。

  1. Now again nothing in the pool, and i say,

    String s = new String("Java"); Now how many objects will be created. Two String object is created.

一个是interned "Java",一个是new String 与"Java"

内容相同
  1. Now again nothing in the pool, and i say,

    String s = new String("Java"); s.intern(); What will the intern method do ?

intern() 方法将:

When the intern method is invoked, if the pool already contains a string equal to this String object as determined by the equals(Object) method, then the string from the pool is returned. Otherwise, this String object is added to the pool and a reference to this String object is returned.

所以在这种情况下,这个字符串被添加到池中并返回对此的引用

最后一个问题:

  1. Now again nothing in the pool, and i say,

    String s = new String("Java"); String s1 = s.intern(); What will happen now?

这里发生的是:

  1. 字符串 "Java" 已添加到池中
  2. 创建新字符串,由相同的 char[] 数组支持 "Java"
  3. s.intern() 在池中查找引用,s1 由内部引用
  4. 赋值

我假设在下面的每个示例中,您每次都在新的 JVM 中加载并执行一次代码。 (我还假设您的代码中没有其他地方使用文字 "Java" ... 因为这会使事情复杂化。)


1) Say if there are no strings in the String constant pool, and if i say,

String s = "Java";

Then how many objects will be created ?

加载方法时会创建一个字符串并将其添加到池中。


2) Now again nothing in the pool, and i say,

String s = new String("Java");

Now how many objects will be created.

加载方法时会创建一个字符串并将其添加到池中。

第二个字符串由 new 在代码为 运行 时创建,并且未添加到池中。


3) Now again nothing in the pool, and i say,

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

What will the intern method do ?

加载方法时会创建一个字符串并将其添加到池中。

第二个字符串由 new 创建,但未添加到池中。

intern调用returns第一个字符串。 (你不保留参考...)


4) Now again nothing in the pool, and i say,

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

What will happen now?

与示例 3 相同。因此,s1 将保存对表示 "Java" 字符串文字的 String 对象的引用。


I read in SCJP5 Kathy Sierra book, that when you create a String with new, then 2 objects are created, one on the heap and one in the pool.

我怀疑这本书说的是否准确。 (你在转述,我认为你转述的有些不准确。)

然而,您的解释大致正确,尽管(这很重要!)表示文字的字符串对象在加载代码片段时创建并添加到池中1, 而不是在执行的时候。


并解决另一个困惑点:

"What i actually meant was that from the answer that you gave, it seems that a String will always be added in the String constant pool."

这是不正确的。这是一种错误的概括。

虽然上述所有 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.

中创建一个second 字符串

1 - 显然,在某些 JVM 中,字符串文字的创建和驻留是 lazily 完成的,因此无法 100% 确定实际执行的时间发生。然而,它只会出现一次(每个 class 引用文字),无论代码片段被 JVM 执行了多少次。

2 - 无法将字符串 new 放入字符串池中。这实际上违反了 JLS。 new 操作被 JLS 指定为 always 创建一个新对象。

String strObject = new String("Java");

String strLiteral = "Java";

这两个表达式都为您提供 String 对象,但它们之间存在细微差别。
当您使用 new() 运算符创建 String 对象时,它总是在 heap memory.

中创建一个新对象

另一方面,如果您使用字符串文字语法创建对象,例如"Java",它可能 return 来自 String pool 的现有对象(Perm gen space 中 String 对象的缓存,现在已移至最近的堆 space Java 发布),如果它已经存在。否则它将创建一个新的字符串对象并放入字符串池中以供将来重新使用。

  1. String s = "Java";

将在 Pool 中创建一个对象。

  1. 现在池子里又什么都没有了,我说,

String s = new String("Java");

将在 Heap

中创建一个对象
  1. 现在池子里又什么都没有了,我说,

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

实习生方法会做什么?
intern() 方法会将 Sting 对象复制到池中,但它没有用,因为它未被引用,因此只有 Heap

中的对象
  1. 现在池子里又什么都没有了,我说,

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

现在会发生什么?

将创建 Heap 中的一个对象和 Pool 中的一个对象。