2012-06-22 25 views
11

Vì hầu hết mọi người đều biết các chuỗi trong Java là không thay đổi. Gần đây tôi đã khám phá ra điều gì đó có thể gợi ý rằng nó không phải lúc nào cũng đúng. Hãy thử mã này:Các chuỗi có thể thay đổi trong Java

System.out.println("-------- BEFORE MODIFICATIONS --------"); 
String beforeTest = new String("Original"); 
System.out.println(beforeTest); 
java.lang.reflect.Field valueField = String.class.getDeclaredField("value"); 
valueField.setAccessible(true); 
valueField.set("Original", "Modified".toCharArray()); 
System.out.println("-------- AFTER MODIFICATIONS --------"); 
System.out.println(beforeTest); 
System.out.println("Original"); 
String test = new String("Original"); 
System.out.println(test); 
String test2 = new String("Original 2"); 
System.out.println(test2); 

đầu ra sẽ là:

-------- BEFORE MODIFICATIONS -------- 
Original 
-------- AFTER MODIFICATIONS -------- 
Original 
Modified 
Modified 
Original 2 

làm việc như thế này lừa? Làm thế nào để JVM biết đối tượng nào cần được thay đổi và cái nào không? Cơ chế nào dưới sự che chở của thủ thuật này? Tại sao chuỗi beforeTest không được thay đổi? Thủ thuật này có thực sự vi phạm nguyên tắc strings are immutable không?

+6

Phản ánh là ma thuật voodoo đen. –

+1

@HovercraftFullOfEels, Reflection hoàn toàn được xác định rõ. Chỉ khi bạn vi phạm 'riêng tư 'bằng cách gọi' setAccessible' là những bất biến của lớp lõi đi ra ngoài cửa sổ. –

+3

@MikeSamuel Reflection * chính nó * được xác định rõ. * Sử dụng * nó không phải là, do đó voodoo một lần mucking bắt đầu unmuckable. Tôi có toàn bộ khuôn khổ cho điều này (Muckito). –

Trả lời

17

Chuỗi ký tự được tập trung vào một hồ bơi. Điều này có nghĩa là khi bạn viết

String s1 = "Foo"; 
String s2 = "Foo"; 
String s3 = new String("Foo"); 

s1 và s2 tham chiếu đến cùng một đối tượng String và s3 tham chiếu đến một đối tượng khác, được hỗ trợ bởi một mảng char khác.

Trong mã của bạn, bạn vi phạm các bất biến của String bằng cách sửa đổi mảng char riêng chứa các ký tự của thể hiện kiểu chữ "Gốc". Nhưng kể từ beforeTest đề cập đến một thể hiện String khác, nó không được sửa đổi.

Tính bất biến được thực hiện bằng cách giữ trường riêng tư thành đối tượng và không cung cấp bất kỳ phương pháp nào để sửa đổi trạng thái riêng tư này. Bằng cách sử dụng sự phản chiếu, bạn phá vỡ tất cả các quy tắc đóng gói, và do đó bạn có thể vi phạm bất biến.

+0

Không phải là trường hợp thứ ba (tham khảo thử nghiệm) cũng trỏ đến trường hợp mới? Nếu char nguyên gốc "" được thay thế bằng "Đã sửa đổi" không nên trước khi giá trị được cập nhật (vì cùng một chữ được truyền qua ví dụ)? – kosa

+0

Biến 'test' được khởi tạo thành bản sao của chuỗi ký tự" Gốc ". Nhưng bạn đã sửa đổi nội dung của nó thành "Đã sửa đổi" khi bản sao được tạo. Vì vậy, đó là một bản sao của "Sửa đổi". 'beforeTest' cũng là bản sao của chuỗi" Gốc ", nhưng bản sao đã được tạo trước khi bạn sửa đổi nội dung của nó. –

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