【问题标题】:Need to know about String, String Constant pool and String intern method [duplicate]需要了解字符串、字符串常量池和字符串实习方法 [重复]
【发布时间】:2019-01-03 08:13:50
【问题描述】:
  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 个对象,一个在堆上,一个在池中。

【问题讨论】:

  • 在 Java 的正常使用中,你几乎不应该关心字符串实习,你的代码也不应该包含 String.intern()(与所有规则一样,有例外,但除非你有一个非常好的理由)。不要沉迷于这样的事情,在学习 Java 编程时,它真的不重要。
  • 同意。不幸的是,SCJP 考试会问一些愚蠢的问题,需要这样的知识。更不幸的是,这些问题经常以模棱两可的方式提出......因此没有一个正确的答案。
  • @MarkRotteveel,我想重新提出这个问题,因为它比固定的问题更详细,更实用,你不这么认为吗?
  • @AndrewTobilko - 我认为它应该保持关闭。不需要更多的答案。严重地。是的,细节不同,是的回答对OP很有用,但信息都在原始问答中。 (可以说,这只是原作的插图。)
  • @AndrewTobilko 我选择的副本提出了同样的问题,它只是在没有将其分解为单独步骤的情况下完成了它。那里的答案也充分解释了它。我认为没有充分的理由重新开放。

标签: java string string-interning string-pool


【解决方案1】:

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


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

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 将持有对代表 "Java" 字符串文字的 String 对象的引用。


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

我怀疑这本书是否准确地表达了这一点。 (你在解释,我认为你的解释有些不准确。)

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


为了解决另一个混淆点:

“我的真正意思是,从你给出的答案来看,字符串常量池中似乎总是会添加一个字符串。”

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

虽然上述所有 4 种情况都是如此,但其他情况并非如此。这取决于原始字符串的来源。在典型的应用程序中,大多数文本数据都是从文件、套接字或用户界面中读取的。发生这种情况时,字符串是从字符数组直接或通过库调用创建的。

这是一个简单(但不切实际)的示例,展示了从其组成字符创建字符串。

String s = new String(new char[]{'J', 'a', 'v', 'a'});

在上面的sn-p中,只创建了一个String,并且不在String pool中。如果您希望生成的字符串在字符串池中,您需要显式调用intern,如下所示:

String s = new String(new char[]{'J', 'a', 'v', 'a'});
s = s.intern();

... 这将(如有必要)在字符串池中创建一个 second 字符串2.


1 - 显然,在某些 JVM 中,字符串文字的创建和实习是懒惰地完成的,因此无法 100% 确定何时实际发生。但是,它只会发生一次(每个引用文字的类),无论代码片段被 JVM 执行多少次。

2 - 没有办法将new 一个字符串放入字符串池。这实际上违反了 JLS。 new 操作由 JLS 指定为总是创建一个新对象。

【讨论】:

  • 嗨斯蒂芬,谢谢你的回答。所有的案例都是相互独立的。据我了解。在第一种情况下,“Java”对象将在池中创建,s 将指向它。在第二种情况下,“Java”对象将在堆和池中创建。因此创建了 2 个对象。 s 将指向堆中的对象,而池中的对象将没有引用。对于第三种情况,将再次创建 2 个对象。然后实习生方法将尝试将“Java”对象放入池中,但它已经存在。所以实习生不会做很多这样的事情。
  • 现在在第 4 种情况下,将创建 2 个对象。实习生在这里也不会有任何帮助。 s1 将指向池中的对象, s 指向堆中的对象。我说的对吗?
  • 是的。 intern() 在第 3 和第 4 种情况下同样没用。而new 在所有情况下也是无用的!这些例子与有用性无关。他们是关于了解字符串池和实习的工作的血腥细节。但实际上,对于 99.9% 的实际程序,您需要知道一件事:不要使用 == 来测试字符串相等性。
  • 感谢斯蒂芬的澄清。我检查了您标记为重复的问题的答案,其中指出:“请注意,您可以在 String 对象上调用 intern()。如果 String 对象不存在,这会将其放入池中,并返回对池化字符串的引用。”据我所知,每当我创建一个字符串时,无论是文字还是新字符串,它都会始终将其放入字符串常量池中。 “如果 String 对象不存在,这会将其放入池中”。但它总是在游泳池里。那么 intern 方法的意义何在?
  • dup Q&A 中所说的是正确的。 “据我所知,每当我创建一个字符串时,无论是文字还是新字符串,它都会始终将其放入字符串常量池中。” - 这是不正确的。事实上,我对这个问题的回答是说这种说法也是不正确的。 new 的结果不会放入字符串池中。 (并且在 JVM 中没有“字符串常量池”之类的东西。)如果您不相信我们的答案或不仔细阅读它们,我们将无法“清除您的疑问” !
【解决方案2】:
  1. 那么会创建多少个对象呢?

池中有一个String

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

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

  1. intern 方法会做什么?

它将尝试将"Java" 放入池中,在那里找到另一个"Java",从步骤1 返回对该"Java" 的引用。

  1. 现在会发生什么?

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

【讨论】:

  • 您好安德鲁,感谢您的及时回答。但我的疑问还没有消除。
  • @RohitT,提出你的问题,伙计。我们会为他们找到答案。
  • @RohitT:那你有什么疑问?
【解决方案3】:
  1. 说如果String常量池中没有字符串,如果我说,

    字符串 s = "Java";

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

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

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

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

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

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

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

intern() 方法将:

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

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

最后一个问题:

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

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

这里发生的是:

  1. 字符串“Java”已添加到池中
  2. 新字符串已创建,由相同的 char[] 数组“Java”支持
  3. s.intern() 在池中查找引用,s1 由实习引用分配

【讨论】:

    【解决方案4】:
    String strObject = new String("Java");
    

    String strLiteral = "Java";
    

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

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

    1. 字符串 s = "Java";

    将在Pool 中创建一个对象。

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

    String s = new String("Java");

    将在Heap 中创建一个对象

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

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

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

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

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

    现在会发生什么?

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-09-14
      • 1970-01-01
      • 2013-10-25
      • 2012-12-18
      • 1970-01-01
      • 2014-06-08
      相关资源
      最近更新 更多