关于Java的字符串池的问题

时间:2009-12-10 15:51:06

标签: java string string-pool

考虑以下代码:

String first = "abc"; 
String second = new String("abc");

使用new关键字时,Java会再次创建abc String吗? 这会存储在常规堆还是String池中? String池中将有多少String个结束?

7 个答案:

答案 0 :(得分:94)

如果您使用new关键字,则会创建一个新的String对象。请注意,对象始终位于堆上 - 字符串池不是与堆分开的单独内存区域。

字符串池就像一个缓存。如果你这样做:

String s = "abc";
String p = "abc";

然后Java编译器足够智能,只能生成一个String对象,而sp都将引用同一个String对象。如果你这样做:

String s = new String("abc");

然后池中会有一个String对象,代表文字"abc"的对象,并且会有一个单独的String对象,而不是在池中,包含合并对象内容的副本。由于String在Java中是不可变的,所以你不会通过这样做获得任何东西;调用new String("literal")在Java中永远不会有意义,并且不必要地效率低下。

请注意,您可以在intern()对象上调用String。这将把String对象放入池中(如果它尚不存在),并返回对池化字符串的引用。 (如果它已经在池中,它只返回对已存在的对象的引用)。有关详细信息,请参阅该方法的API文档。

另见String interning(维基百科)。

答案 1 :(得分:12)

字节码中,第一个作业是:

  Code:
   0:   ldc     #2; //String abc
   2:   astore_1

而第二个是:

   3:   new     #3; //class java/lang/String
   6:   dup
   7:   ldc     #2; //String abc
   9:   invokespecial   #4; //Method java/lang/String."":(Ljava/lang/String;)V

所以第一个是在池中(位置#2),而第二个将存储在堆中。

修改

由于CONSTANT_String_info store the index as U2(16位,无符号),池可以包含最多2**16 = 65535个引用。如果你关心here more limits of the JVM

答案 2 :(得分:7)

每次代码创建字符串文字

例如:

String str="Hello"; (string literal) 

JVM首先检查字符串文字池。如果池中已存在该字符串,则返回对池化实例的引用。如果池中不存在该字符串,则新的String对象将实例化,然后放入池中。 Java可以进行这种优化,因为字符串是不可变的,可以共享而不用担心数据损坏

答案 3 :(得分:3)

String strObject = new String("Java");

String strLiteral = "Java";

两个表达式都为您提供了String对象,但它们之间存在细微差别。使用new()运算符创建String对象时,它总是在堆内存中创建一个新对象。另一方面,如果使用String文字语法创建对象,例如" Java",它可以返回String池中的现有对象(Perm gen空间中的String对象的缓存,现在它已移动到最近Java版本中的堆空间),如果它已经存在。

答案 4 :(得分:2)

你应该使用new String(foo)的唯一时间是你想要破坏==,这是一个奇怪的情况,或者当foo是一个更大的字符串,具有有限的生命周期的子字符串,例如

String mystring;
{
   String source = getSomeHeinouslyLargeString();
   mystring = new String(source.substring(1,3));
}

答案 5 :(得分:0)

虽然很晚,但对于仍然遇到此问题的人可能会有用:

String first = "abc";
//One instance object in pool created. Instance variable “first” refers/points to pooled object

String second = new String("abc");    
//One instance object in heap created. Object in pool creation step will be skipped on account of first statement.

因此总共将创建2个实例对象。一个在池中,另一个在堆中

详细说明

  

字符串优先=" abc&#34 ;;

这里是一个包含内容" abc"的字符串对象。在池中创建。实例变量“first”将指向内容为“abc”的池对象。

  

String second = new String(" abc");

这里是另一个带有内容" abc"的字符串对象。将在堆中创建。实例变量“second”将指向内容为“abc”的堆对象。包含内容" abc"的字符串对象由于第一个声明,将跳过池中的创建。原因如下。

<强>原因

如果假设先前语句(String first =&#34; abc&#34 ;;)不具有相同的内容,那么通常使用“new”关键字,将在堆(外部池)中创建一个2个字符串对象,池中的另一个(堆的子集区域)。 实例变量&#34; second&#34;应该只指向堆对象,而不管对象是否在池中。

现在由于先前语句(String first =&#34; abc&#34 ;;)的存在与新String中的内容相同(&#34; abc&#34;),只有一个对象(含有内容) &#34; abc&#34;)保留在池中。 因此,由于第一个语句,第二个语句将只创建一个对象而不是2,并且该对象在堆中。将跳过池对象创建。

//Additional Test on the concept
System.out.println(first==second);  //returns false. Because first points to pool object while second points to heap object. And both objects are different (on account of different memory locations).

second = second.intern();           //After interning, second now points to pool object. Note: intern is used so that reference variable points to pool area object and not heap object. Clearly it is applicable when we use new keyword.

System.out.println(first==second);  //returns true. Because now both first and second objects now points to same pool object.

答案 6 :(得分:0)

String first = "abc"; 
String second = new String("abc");

在第一种情况下,只有一个对象将在Pool中创建。 在第二种情况下,两个对象将在池中创建一个(如果以前在池中不存在),而在堆中创建一个。

当您使用双引号ex:“abc”传递任何值时,您将在池中创建一个对象并将其传递给字符串构造函数,以便在堆中创建具有相同值的新对象。

如果您看到字符串构造函数,则可以看到它接受字符串。那串是什么?在创建之前,该字符串对象是什么。它只是存储在String Constant池中的对象。