2015-04-26 32 views
14

Tôi thực sự bối rối với cách hoạt động của Java trong string interning. Khi tôi viết:Việc thực hiện chuỗi ký tự được thực hiện tại thời gian biên dịch trong Java?

String a = "ABC"; 
String b = "ABC"; 

if (a==b) 
    System.out.println("Equal"); 

Trình biên dịch lưu chuỗi ký tự "ABC" vào nhóm hằng số chuỗi tại thời gian biên dịch không?

Nghe có vẻ phi logic, vì tôi nghĩ rằng chuỗi hằng số chuỗi được JVM tạo ra khi chạy, và tôi không thấy làm thế nào có thể nếu nó được thực hiện tại thời gian biên dịch vì trình biên dịch Java thậm chí không gọi JVM .

Nếu nó không được thực hiện tại thời gian biên dịch và nó được thực hiện tại thời gian chạy thì tại sao sau đây trở về sai (lấy từ this answer)?

// But .substring() is invoked at runtime, generating distinct objects 
"test" == "!test".substring(1) // --> false 

Nếu được thực hiện trong thời gian chạy thì tại sao JVM không thể nhận ra rằng chúng là cùng một chuỗi?

Tôi thực sự bối rối về cách thức thực thi chuỗi hoạt động trong Java và nơi lưu trữ chính xác nhóm chuỗi Java.

+0

Các liên kết sau đây là sâu sắc: http://stackoverflow.com/questions/513832/ how-do-i-compare-strings-in-java – Zyn

+0

Tôi không chắc chắn về phần đầu tiên của câu hỏi của bạn, nhưng 'chuỗi con' trả về một đối tượng * mới *, và vì vậy trong khi nội dung của cả hai chuỗi khớp với' test ', vì chúng không phải là cùng một đối tượng' == 'trả về false. –

+2

Đó là trình biên dịch. Tôi không hiểu tại sao bạn nói rằng nó không thể đặt cả hai chuỗi trong chuỗi hằng số chuỗi.Trình biên dịch sẽ đặt các chuỗi không đổi bên trong một số vị trí bộ nhớ, sau đó khi khởi chạy chương trình, JVM sẽ tải bộ nhớ đó và tạo nhóm không đổi được sử dụng trong thời gian chạy, nhưng hồ bơi được thiết lập bởi trình biên dịch. – Bakuriu

Trả lời

18

Trình biên dịch đặt các chuỗi ký tự trong tệp lớp (và chỉ các chuỗi duy nhất, nó hợp nhất tất cả các chữ tương đương); JVM tải các chuỗi đó vào nhóm chuỗi khi tệp lớp được tải.

Nếu được thực hiện trong thời gian chạy thì tại sao JVM không thể nhận ra rằng chúng là cùng một Chuỗi.

Bởi vì chuỗi được trả về bởi .substring chưa được thực tập nội trú, và do đó là một đối tượng khác với "test" chuỗi tương đương trong hồ bơi chuỗi. Nếu bạn thực tập nội trú nó, bạn sẽ nhận được true:

"test" == "!test".substring(1).intern() // true 

mục §4.4 of the JLS§5.3 of the JVM spec trông có liên quan.


Chỉ cần được rõ ràng: Các cách chính xác để so sánh chuỗi trong Java là sử dụng phương pháp .equals hoặc tương tự, không ==. Sử dụng == với các phiên bản chuỗi là thường là không chính xác. (Trừ khi bạn đang chơi với sự hiểu biết khi nào và như thế nào mọi thứ đang thực tập nội trú ...)

+1

Tài liệu về chuỗi con @ http://docs.oracle.com/javase/7/docs/api/java/lang/String.html#substring(int) nêu rõ rằng nó trả về một đối tượng chuỗi * mới *. –

+0

Chỉ cần thêm một số chi tiết. Câu trả lời hay. –

+0

@ T.J.Crowder để 'intern()' tránh đối tượng mới phải không? –

0

Tôi đã kiểm tra .class cho

String a = "ABC"; 
String b = "ABC"; 

và thấy chỉ có một "ABC" trong đó. Đó là javac tạo ra một hằng số của cùng một chuỗi tại thời gian biên dịch.

Nhưng nếu 2 hoặc nhiều lớp có cùng "ABC" liên tục sau đó JVM sẽ đặt chúng ở cùng một vị trí trong hồ bơi chuỗi

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