关于Java的string池的问题

考虑这个代码:

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

当使用new关键字时,Java会再次创buildabc String 。 这将存储在常规的堆或String池? 多less个String将在String池中结束?

如果使用new关键字,则会创build一个新的String对象。 请注意,对象始终在堆上 – string池不是与堆分开的独立内存区域。

string池就像一个caching。 如果你这样做:

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

那么Java编译器足够聪明,只需要创build一个String对象,而sp都将引用同一个String对象。 如果你这样做:

 String s = new String("abc"); 

那么池中将会有一个String对象,表示字面值"abc" ,并且会有一个单独的String对象,不在池中,其中包含池对象内容的副本。 由于String在Java中是不可变的,所以你没有得到任何东西。 调用new String("literal")在Java中永远没有意义,并且不必要的低效。

请注意,您可以调用一个String对象的intern() 。 这会将String对象放在池中,如果它尚不存在,并返回引用到池string。 (如果它已经在池中,它只是返回已经存在的对象的引用)。 有关更多信息,请参阅该方法的API文档。

参见string实习 (维基百科)。

字节码中 ,第一个任务是:

  码:
    0:ldc#2;  //stringabc
    2:astore_1

而第二个是:

    3:新#3;  // class java / lang / String
    6:dup
    7:ldc#2;  //stringabc
    9:invokespecial#4;  //方法java / lang / String。“”:( Ljava / lang / String;)V

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

编辑

由于CONSTANT_String_info 将索引存储为U2 (16位,无符号),因此池可以包含最多2**16 = 65535引用。 如果你在这里关心JVM的更多限制 。

每次您的代码创build一个string文字

例如:

 String str="Hello"; (string literal) 

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

唯一一次你应该使用新的string(foo)是当你想要打破==,这是一个奇怪的情况,或者当foo是一个更大的string,有一个有限的生命周期的子string,如

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

 String strLiteral = "Java"; 

这两个expression式都给你String对象,但是它们之间有细微的差别。 当你使用new()运算符创buildString对象时,它总是在堆内存中创build一个新的对象。 另一方面,如果使用string文字语法(例如“Java”)创build对象,则可以从string池(在Perm gen空间中的一个string对象caching,现在在最近的Java版本中移动到堆空间)返回一个现有对象。 ,如果它已经存在。