关于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
对象,而s
和p
都将引用同一个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版本中移动到堆空间)返回一个现有对象。 ,如果它已经存在。