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

4

4 回答 4

4

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

于 2018-07-26T11:06:01.690 回答
3
  1. 那么会创建多少个对象呢?

游泳池里有一只String

  1. 现在将创建多少个对象?

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

  1. 实习生方法会做什么?

它将尝试将 a"Java"放入池中,在"Java"那里找到另一个,并返回对第 1 步中的引用"Java"

  1. 现在会发生什么?

"Java"from step 1 将返回,现在s1引用它。

于 2018-07-26T10:57:08.963 回答
0
  1. 假设字符串常量池中没有字符串,如果我说,

    字符串 s = "Java";

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

在实习生池中创建了一个 String 对象。 s由该引用指定。

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

    字符串 s = new String("Java"); 现在将创建多少个对象。创建了两个 String 对象。

一个是 interned "Java",一个是 new String ,内容相同"Java"

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

    字符串 s = new String("Java"); s.实习生();实习生方法会做什么?

intern()方法将:

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

所以在这种情况下,这个 String 被添加到池中并返回一个对 this 的引用

最后一个问题:

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

    字符串 s = new String("Java"); 字符串 s1 = s.intern(); 现在会发生什么?

这里发生的是:

  1. 字符串“Java”被添加到池中
  2. 创建新字符串,由相同的char[]数组“Java”支持
  3. s.intern()在池中查找引用s1并由实习引用分配
于 2018-07-26T11:05:41.310 回答
0
String strObject = new String("Java");

String strLiteral = "Java";

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

另一方面,如果您使用字符串字面量语法(例如“Java”)创建对象,它可能会从String pool(Perm gen 空间中的字符串对象缓存,在最近的 Java 版本中现在移动到堆空间)返回一个现有对象,如果它已经存在。否则它将创建一个新的字符串对象并放入字符串池以供将来重用。

  1. 字符串 s = "Java";

将在 中创建一个对象Pool

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

字符串 s = new String("Java");

将创建一个对象Heap

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

字符串 s = new String("Java");
s.实习生();

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

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

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

现在会发生什么?

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

于 2018-07-26T11:12:19.400 回答