JLS
JLS 7 3.10.5定义了它并给出了一个实例:此外,字符串文字总是引用类字符串的同一个实例。这是因为字符串文本-或者更普遍地说,字符串是常量表达式的值(§15.28)-是“内部的”,以便使用String.intern方法共享唯一的实例。
例3.10.5-1。字符串文字
由汇编单位组成的程序(第7.3节):package testPackage;class Test {
public static void main(String[] args) {
String hello = "Hello", lo = "lo";
System.out.print((hello == "Hello") + " ");
System.out.print((Other.hello == hello) + " ");
System.out.print((other.Other.hello == hello) + " ");
System.out.print((hello == ("Hel"+"lo")) + " ");
System.out.print((hello == ("Hel"+lo)) + " ");
System.out.println(hello == ("Hel"+lo).intern());
}}class Other { static String hello = "Hello"; }
汇编单位:package other;public class Other { public static String hello = "Hello"; }
产生输出:true true true true false true
JVMS
JVMS 7 5.1说说实习是神奇而高效地用一个专用的CONSTANT_String_infostruct(与大多数具有更一般表示形式的其他对象不同):字符串文字是对类字符串实例的引用,它来自类或接口的二进制表示中的常数_String_INFO结构(§4.4.3)。ConstantString_INFO结构给出了构成字符串文本的Unicode代码点的顺序。
Java编程语言要求相同的字符串文本(即包含相同的代码点序列的文本)必须引用相同的类字符串实例(JLS§3.10.5)。此外,如果对任何字符串调用方法String.intern,则结果是对如果该字符串以文字形式出现将返回的同一个类实例的引用。因此,以下表达式必须具有true值:("a" + "b" + "c").intern() == "abc"
要派生字符串文本,Java虚拟机将检查CONTER_STRING_INFO结构给出的代码点序列。如果以前在包含Unicode代码序列的类字符串实例上调用了方法String.intern,则String文字派生的结果是对该类字符串实例的引用。
否则,将创建一个类String的新实例,该实例包含由ConstantString_INFO结构提供的Unicode代码点序列;对该类实例的引用是字符串文字派生的结果。最后,调用新字符串实例的intern方法。
字节码
让我们对一些OpenJDK 7字节码进行反编译,以查看实习生的实际情况。
如果我们分解:public class StringPool {
public static void main(String[] args) {
String a = "abc";
String b = "abc";
String c = new String("abc");
System.out.println(a);
System.out.println(b);
System.out.println(a == c);
}}
我们有一个固定的游泳池:#2 = String #32 // abc[...]#32 = Utf8 abc
和main:0: ldc #2 // String abc
2: astore_1 3: ldc #2 // String abc
5: astore_2 6: new #3 // class java/lang/String
9: dup10: ldc #2 // String abc12: invokespecial #4 // Method java/lang/String."":
(Ljava/lang/String;)V15: astore_316: getstatic #5 // Field java/lang/System.out:Ljava/io/PrintStream;19: aload_120:
invokevirtual #6 // Method java/io/PrintStream.println:(Ljava/lang/String;)V23: getstatic #5
// Field java/lang/System.out:Ljava/io/PrintStream;26: aload_227: invokevirtual #6
// Method java/io/PrintStream.println:(Ljava/lang/String;)V30: getstatic #5
// Field java/lang/System.out:Ljava/io/PrintStream;33: aload_134: aload_335: if_acmpne 4238: iconst_139: goto
4342: iconst_043: invokevirtual #7 // Method java/io/PrintStream.println:(Z)V
注意:0和
3*相同
ldc #2常量被加载(文字)
12*创建一个新的字符串实例(与
#2作为论据)
35: a和
c作为常规对象进行比较。
if_acmpne
常量字符串的表示在字节码上非常神奇:它有一个专门的结构,不像常规对象(例如:
new String)
结构指向包含数据的。这是表示字符串的唯一必要数据。
上面的JVMS引用似乎表明,每当指向的UTF 8是相同的,那么相同的实例将被ldc.
我对字段做了类似的测试,并且:static final String s = "abc"通过
非最终字段没有该属性,但仍然可以用
ldc
结语对字符串池有直接的字节码支持,内存表示是有效的。
奖励:将其与整数池,它没有直接的字节码支持(即否)。CONSTANT_String_info模拟)。