2013-01-23 39 views
8

Tôi đọc điều này Questions about Java's String pool và hiểu khái niệm cơ bản về nhóm chuỗi nhưng vẫn không hiểu hành vi.Hành vi của chuỗi hồ bơi

Thứ nhất: nó hoạt động nếu bạn trực tiếp gán giá trị và cả hai s1 và s2 tham khảo cùng một đối tượng trong hồ bơi

String s1 = "a" + "bc"; 
String s2 = "ab" + "c"; 
System.out.println("s1 == s2? " + (s1 == s2)); 

Nhưng sau đó nếu tôi thay đổi chuỗi s1 + = "d", sau đó hồ bơi nên có một đối tượng chuỗi "abcd"? sau đó khi tôi thay đổi s2 + = "d", nó sẽ tìm đối tượng chuỗi "abcd" trong hồ bơi và nên gán đối tượng để s2? nhưng nó không và chúng không được đề cập đến cùng một đối tượng. Tại sao vậy?

String s1 = "abc"; 
String s2 = "abc"; 
System.out.println("s1 == s2? " + (s1 == s2)); 

s1 += "d";     
s2 += "d"; 
System.out.println("s1 == s2? " + (s1 == s2)); 
+0

bản sao có thể có của [Câu hỏi về nhóm chuỗi Java] (http://stackoverflow.com/questions/1881922/questions-about-javas-string-pool) – EJP

+0

@EJP Asker đề cập đến chủ đề đó và nói rằng nó không trả lời câu hỏi của mình. – glomad

Trả lời

7

Chuỗi được đảm bảo được gộp lại khi bạn gọi String.intern() trên một chuỗi.

String s1 = "abcd".intern(); 
String s2 = "abc"; 
s2 += "d"; 
s2 = s2.intern(); 
s1 == s2 // returns true 

Khi biên dịch thấy một hằng số đó là đủ thông minh để tối ưu hóa và hồ bơi chuỗi chữ, ví dụ:

String s1 = "abcd"; 
String s2 = "abcd"; 
s1 == s2 // returns true 

Java Language Specification trạng thái:

Mỗi chuỗi chữ là một tài liệu tham khảo (§ 4.3) cho một cá thể (§4.3.1, §12.5) của chuỗi lớp (§4.3.3). Chuỗi đối tượng có giá trị không đổi. Chuỗi literals-hoặc, thường là, các chuỗi là các giá trị của hằng số cụm từ (§15.28) -are "interned" để để chia sẻ các trường hợp duy nhất, sử dụng phương thức String2internet .

Vì vậy, trong trường hợp s2 += "d", trình biên dịch không thông minh như bạn và chỉ cần gộp chung "d".

+2

Trong khi câu trả lời này nêu rõ sự thật, nó không giải thích được lý do * tại sao * của câu hỏi. – Vulcan

+0

Thú vị, toàn bộ chuỗi hồ bơi có thiếu điểm không? nếu tôi cần thêm .intern() vào mỗi chuỗi đơn? – Jaxox

+5

@ user2005443 Bạn thường không nên thêm 'intern()' vào mỗi chuỗi. Đó là tối ưu hóa sớm. Nếu có một số chuỗi mà bạn biết (hoặc tìm hiểu thông qua lược tả) sẽ được sử dụng rất nhiều, nó có thể giúp cải thiện hiệu suất, nhưng nếu bạn sử dụng nó bừa bãi nó có thể [khá nguy hiểm] (http: //www.codeinstructions. com/2009/01/busting-javalangstringintern-myths.html). – Jeff

0

Đây là dự đoán của tôi:

Chuỗi s1 = "a" + "bc"; Chuỗi s2 = "ab" + "c";

Tôi nghĩ rằng đó là thời gian biên dịch được xác định để sản xuất cùng một chuỗi và do đó chỉ có một đối tượng được thực hiện cho cả hai. Nhưng khi bạn thêm "d" cho cả hai chuỗi, điều này được thực hiện riêng biệt cho cả hai chuỗi (vì nó được thực hiện trong thời gian thực, có thể có những thứ như ngoại lệ làm gián đoạn nó vv, vì vậy nó không thể làm trước nó được.).) và vì vậy nó không tự động làm cho chúng tham chiếu một đối tượng.

+0

Tại sao nên đoán? Tất cả được mô tả trong JLS. – EJP

3

Tôi không chắc chắn về điều này, vì vậy đây là khá nhiều suy đoán, nhưng tôi nghi ngờ rằng có thể có một số thủ thuật biên dịch xảy ra trong ví dụ đầu tiên (trong đó nội tuyến và khá rõ ràng những gì đang xảy ra), nhưng không phải đủ thông minh để kéo nó ra trong ví dụ thứ hai (nơi nó không quá rõ ràng).

Nếu tôi đúng, trình biên dịch sẽ thấy "a" + "bc" và chỉ nén xuống thời gian biên dịch thành "abc" hoặc xem hai dòng và gộp chuỗi bằng cách nhận ra chúng sẽ được sử dụng. Tôi cá cược trước đây ..

Không phải tất cả các chuỗi nhất thiết phải được gộp chung.

+7

Đó là chính xác, trình biên dịch liên tục gấp trên hằng số biên dịch thời gian và đặt chỉ là một chuỗi, "abc", vào hồ bơi liên tục cho lớp. Tôi tin rằng tất cả các chuỗi đến từ các hồ bơi liên tục được interned. Các chuỗi khác, được tạo tại thời gian chạy, không được thực hiện trừ khi bạn gọi String # intern một cách rõ ràng. –

+0

Đó thực sự là những gì sẽ xảy ra. Nếu bạn kiểm tra bytecode, bạn sẽ thấy rằng "a" + "bc" được dịch sang một lệnh ldc duy nhất (đẩy một hằng số), trong khi lệnh khác s1 + "d" dịch sang một cuộc gọi đến StringBuilder. – Gothmog

2

Xem tài liệu cho String#intern(). Dòng cuối cùng có trạng thái:

Tất cả các chuỗi ký tự và các biểu thức hằng số có giá trị chuỗi là được thực hiện.

Ví dụ += không phải là chuỗi chữ cũng như biểu thức hằng số có giá trị chuỗi, vì vậy nó không được đặt trong nhóm Chuỗi.

2

Trình biên dịch có thể thực hiện đánh giá liên tục nhưng không phải trong trường hợp bạn thay đổi các giá trị

Hãy thử thay vì sau và xem những gì sẽ xảy ra nếu bạn thả final từ một trong hai biến.

final String s1 = "abc"; 
final String s2 = "abc"; 
System.out.println("s1 == s2? " + (s1 == s2)); 

String s3 = s1 + "d";     
String s4 = s2 + "d"; 
System.out.println("s3 == s4? " + (s3 == s4)); 
0

Tôi nghĩ rằng những gì xảy ra ở đây là: 1. cho String s1 = "a" + "bc"; Chuỗi s2 = "ab" + "c"; trình biên dịch Java là đủ thông minh để biết rằng giá trị văn chương của s1 và s2 đều giống nhau, do đó trình biên dịch chỉ cho họ biết đến giá trị văn chương cùng trong hồ bơi chuỗi

  1. cho s1 + = "d";
    s2 + = "d";

không có cách nào trình biên dịch biết nếu s1 và s2 sẽ kết thúc được giá trị như nhau, Khi chạy, trừ khi bạn gọi String.intern(), JVM sẽ không kiểm tra chuỗi hồ bơi đen để xem giá trị đã có.

Các vấn đề liên quan