JLS
JLS 7 3.10.5 định nghĩa nó và đưa ra một ví dụ thực tế:
Hơn nữa, một chuỗi ký tự luôn luôn đề cập đến cùng một thể hiện của Chuỗi lớp. Điều này là do các chuỗi ký tự - hay nói chung hơn là các chuỗi là các giá trị của biểu thức hằng (§15.28) - được "thực hiện" để chia sẻ các thể hiện duy nhất, sử dụng phương thức String.i INTERN.
Ví dụ 3.10.5-1. Chuỗi ký tự
Chương trình bao gồm đơn vị biên dịch (§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"; }
và đơn vị biên dịch:
package other;
public class Other { public static String hello = "Hello"; }
tạo ra đầu ra:
true true true true false true
Liên doanh
JVMS 7 5.1 nói rằng thực tập được thực hiện một cách kỳ diệu và hiệu quả với một CONSTANT_String_info
cấu trúc chuyên dụng (không giống như hầu hết các đối tượng khác có các biểu diễn chung hơn):
Một chuỗi ký tự là một tham chiếu đến một thể hiện của Chuỗi lớp và được lấy từ cấu trúc CONSTANT_String_info (§4.4.3) trong biểu diễn nhị phân của một lớp hoặc giao diện. Cấu trúc CONSTANT_String_info đưa ra chuỗi các điểm mã Unicode cấu thành chuỗi ký tự.
Ngôn ngữ lập trình Java yêu cầu các chuỗi ký tự chuỗi giống hệt nhau (nghĩa là các chữ có chứa cùng một chuỗi các điểm mã) phải tham chiếu đến cùng một thể hiện của Chuỗi lớp (JLS §3.10.5). Ngoài ra, nếu phương thức String.i INTERN được gọi trên bất kỳ chuỗi nào, kết quả là một tham chiếu đến cùng thể hiện của lớp sẽ được trả về nếu chuỗi đó xuất hiện dưới dạng một chữ. Do đó, biểu thức sau phải có giá trị đúng:
("a" + "b" + "c").intern() == "abc"
Để lấy được một chuỗi ký tự, Máy ảo Java kiểm tra chuỗi các điểm mã được đưa ra bởi cấu trúc CONSTANT_String_info.
Nếu phương thức String.i INTERN trước đây đã được gọi trong một thể hiện của Chuỗi lớp chứa một chuỗi các điểm mã Unicode giống hệt với cấu trúc CONSTANT_String_info, thì kết quả của dẫn xuất chuỗi ký tự là một tham chiếu đến cùng thể hiện của Chuỗi lớp.
Mặt khác, một thể hiện mới của Chuỗi lớp được tạo có chứa chuỗi các điểm mã Unicode được cung cấp bởi cấu trúc CONSTANT_String_info; một tham chiếu đến thể hiện của lớp đó là kết quả của đạo hàm chuỗi. Cuối cùng, phương thức intern của thể hiện String mới được gọi.
Mã byte
Chúng ta hãy dịch ngược một số mã byte OpenJDK 7 để xem thực tập.
Nếu chúng ta dịch ngược:
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);
}
}
chúng tôi có trên nhóm liên tục:
#2 = String #32 // abc
[...]
#32 = Utf8 abc
và 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: dup
10: ldc #2 // String abc
12: invokespecial #4 // Method java/lang/String."<init>":(Ljava/lang/String;)V
15: astore_3
16: getstatic #5 // Field java/lang/System.out:Ljava/io/PrintStream;
19: aload_1
20: invokevirtual #6 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
23: getstatic #5 // Field java/lang/System.out:Ljava/io/PrintStream;
26: aload_2
27: invokevirtual #6 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
30: getstatic #5 // Field java/lang/System.out:Ljava/io/PrintStream;
33: aload_1
34: aload_3
35: if_acmpne 42
38: iconst_1
39: goto 43
42: iconst_0
43: invokevirtual #7 // Method java/io/PrintStream.println:(Z)V
Lưu ý cách làm:
0
và 3
: ldc #2
hằng số tương tự được tải (bằng chữ)
12
: một phiên bản chuỗi mới được tạo (với #2
đối số)
35
: a
và c
được so sánh như các đối tượng thông thường vớiif_acmpne
Việc biểu diễn các chuỗi không đổi là khá kỳ diệu trên mã byte:
và trích dẫn của JVMS ở trên dường như nói rằng bất cứ khi nào Utf8 được chỉ ra là giống nhau, thì các thể hiện giống hệt nhau được tải bởi ldc
.
Tôi đã thực hiện các bài kiểm tra tương tự cho các trường và:
static final String s = "abc"
trỏ đến bảng hằng số thông qua Thuộc tính ConstantValue
- các trường không phải là cuối cùng không có thuộc tính đó, nhưng vẫn có thể được khởi tạo với
ldc
Kết luận : có hỗ trợ mã byte trực tiếp cho nhóm chuỗi và biểu diễn bộ nhớ là hiệu quả.
Phần thưởng: so sánh với nhóm Integer , không có hỗ trợ mã byte trực tiếp (nghĩa là không có CONSTANT_String_info
tương tự).