什么是Java中的字符串池?

时间:2010-09-27 05:34:40

标签: java

我对Java中的StringPool感到困惑。我在阅读Java中的String章节时遇到过这个问题。请以外行的方式帮助我理解StringPool实际上做的事情。

4 个答案:

答案 0 :(得分:118)

打印true(即使我们不使用equals方法:比较字符串的正确方法)

    String s = "a" + "bc";
    String t = "ab" + "c";
    System.out.println(s == t);

当编译器优化您的字符串文字时,它会发现st都具有相同的值,因此您只需要一个字符串对象。这是安全的,因为String在Java中是不可变的 结果,st都指向同一个对象并保存了一些小内存。

名称'字符串池'来自这样的想法:所有已定义的字符串都存储在某个“池”中,并且在创建新的String对象编译器之前检查是否已经定义了这样的字符串。

答案 1 :(得分:36)

我不认为它实际上做得太多,看起来它只是字符串文字的缓存。如果你有多个字符串的值是相同的,它们都将指向字符串池中相同的字符串文字。

String s1 = "Arul"; //case 1 
String s2 = "Arul"; //case 2 

在案例1中,文字s1是新创建的并保存在池中。但在案例2中,文字s2引用s1,它不会创建新的。

if(s1 == s2) System.out.println("equal"); //Prints equal. 

String n1 = new String("Arul"); 
String n2 = new String("Arul"); 
if(n1 == n2) System.out.println("equal"); //No output.  

http://p2p.wrox.com/java-espanol/29312-string-pooling.html

答案 2 :(得分:17)

让我们从虚拟机规范的引用开始:

  

加载包含String文字的类或接口可能会创建一个新的String对象(第2.4.8节)来表示该文字。如果已经创建了一个String对象来表示该文字的上一个匹配项,或者如果已在表示与该文字相同的字符串的String对象上调用了String.intern方法,则可能不会发生这种情况。

这可能不会发生 - 这是一个提示,String个对象有一些特殊之处。通常,调用构造函数将始终创建该类的新实例。字符串不是这种情况,尤其是在使用文字“创建”String对象时。这些字符串存储在全局存储(池)中 - 或者至少引用保存在池中,并且每当需要已知字符串的新实例时,vm将从池中返回对该对象的引用。在伪代码中,它可能是这样的:

1: a := "one" 
   --> if(pool[hash("one")] == null)  // true
           pool[hash("one") --> "one"]
       return pool[hash("one")]

2: b := "one" 
  --> if(pool[hash("one")] == null)   // false, "one" already in pool
        pool[hash("one") --> "one"]
      return pool[hash("one")] 

因此,在这种情况下,变量ab会保留对相同对象的引用。在这种情况下,我们有(a == b) && (a.equals(b)) == true

如果我们使用构造函数,则情况并非如此:

1: a := "one"
2: b := new String("one")

同样,在池上创建"one",然后我们从同一个文字创建一个新实例,在这种情况下,它会导致(a == b) && (a.equals(b)) == false

那么为什么我们是否有字符串池?字符串,尤其是字符串文字广泛用于典型的Java代码中。而且他们是不变的。并且不可变允许缓存String以节省内存并提高性能(减少创建工作量,减少垃圾收集)。

作为程序员,我们不必太在意字符串池,只要我们记住:

  • (a == b) && (a.equals(b))可能是truefalse始终使用equals来比较字符串)
  • 不要使用反射来更改字符串的后备char[](因为您不知道使用该字符串的人是谁)

答案 3 :(得分:16)

当JVM加载类或以其他方式查看文字字符串或某些代码intern是字符串时,它会将字符串添加到一个主要隐藏的查找表中,该表具有每个此类字符串的一个副本。如果添加了另一个副本,则运行时会对其进行排列,以便所有文字引用相同的字符串对象。这被称为“实习”。如果你说像

这样的话
String s = "test";
return (s == "test");

它将返回true,因为第一个和第二个“测试”实际上是同一个对象。通过这种方式比较实习字符串可以比String.equals更快 ,因为只有一个参考比较,而不是一堆char比较。

你可以通过调用String.intern()向游泳池中添加一个字符串,这将为你提供字符串的汇集版本(这可能是你实习的同一个字符串,但你依旧是疯了在那个 - 你经常不能确切地确定已经加载了什么代码并且直到现在运行并且实际上是相同的字符串)。池化版本(从intern返回的字符串)将等于任何相同的文字。例如:

String s1 = "test";
String s2 = new String("test");  // "new String" guarantees a different object

System.out.println(s1 == s2);  // should print "false"

s2 = s2.intern();
System.out.println(s1 == s2);  // should print "true"