需要了解String,String常量池和String实习生方法

时间:2018-07-26 10:47:46

标签: java string string-interning string-pool

  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)的书中读到的那样,当您用新的字符串创建一个字符串时,会创建2个对象,一个在堆上,一个在池中。

4 个答案:

答案 0 :(得分: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的书,当您使用new创建一个String时,会创建2个对象,一个在堆上,一个在池中。

我怀疑这本书到底是怎么说的。 (您在解释,我认为您的解释有些不准确。)

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


并要解决另一个困惑点:

  

“我的实际意思是,从您给出的答案来看,似乎将始终在String常量池中添加一个String。”

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

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

这是一个简单(但不切实际)的示例,显示了根据其组成字符创建String的情况。

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中,懒惰的创建和内部字符串文字的创建是很懒惰的,因此当它实际发生时不可能百分百确定。但是,无论代码片段被JVM执行多少次,它只会发生一次(每个引用文字的类)。

2-无法将new的字符串插入字符串池。实际上,这将违反JLS。 JLS将new操作指定为始终创建新对象。

答案 1 :(得分:3)

  
      
  1. 那么将创建多少个对象?
  2.   

池中有一个String

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

将创建一个String,池中仍然有一个String

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

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

  
      
  1. 现在会发生什么?
  2.   

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

答案 2 :(得分:0)

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

         

    String s =“ Java”;

  2.   
     

那么将创建多少个对象?

在内部池中创建一个String对象。 s由该引用分配。

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

         

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

  2.   

一个被"Java"拘禁,另一个是"Java"内容相同的新字符串

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

         

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

  2.   

intern()方法将:

  

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

因此,在这种情况下,此字符串将添加到池中,并返回对此的引用

最后一个问题:

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

         

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

  2.   

这里发生的是:

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

答案 3 :(得分:0)

String strObject = new String("Java");

String strLiteral = "Java";

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

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

  
      
  1. 字符串s =“ Java”;
  2.   

将在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”);
  字符串s1 = s.intern();

现在会发生什么?

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