2012-06-22 17 views
11

Java'daki dizeler neredeyse herkesin bildiği gibi değişmez. Son zamanlarda her zaman doğru olmadığını düşündürecek bir şey keşfettim. en bu kodu deneyelim:Java'da değişken dizgiler

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); 

çıkışı olacaktır:

bu hile nasıl çalışır
-------- BEFORE MODIFICATIONS -------- 
Original 
-------- AFTER MODIFICATIONS -------- 
Original 
Modified 
Modified 
Original 2 

? JVM hangi nesnelerin değiştirileceğini ve hangilerinin bilinmemesi gerektiğini nasıl biliyor? Bu numaranın başlığı altında hangi mekanizma var? Neden zaten oluşturulmuş beforeTest dize değişmedi? Bu hile gerçekten strings are immutable ilkesini derogate ediyor mu?

+6

Yansıma kara büyü voodoo. –

+1

@HovercraftFullOfEels, Yansıma mükemmel bir şekilde tanımlanmıştır. Sadece "özel" yi "setAccessible" ile çağırarak, çekirdek sınıf değişmezlerinin pencereden dışarı çıktığını gösterir. –

+3

@MikeSamuel Reflection * kendisi * iyi tanımlanmış. * Kullanarak değil, bu yüzden bir zamanlar mucizevi olmayan başlangıçlar için voodoo. Bunun için bütün bir çerçevem ​​var (Muckito). –

cevap

17

Dize değişmezleri bir havuzda tutulur. Bu

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

s1 yazmak ve s2 aynı String nesnesi bakın ve S3 bir karakter dizisi ile desteklenen başka bir ifade eder zaman anlamına gelir.

Kodunuzda, "Orijinal" Dize değişmezi örneğinin karakterlerini tutan özel karakter dizisini değiştirerek, String'in değişmezlerini ihlal edersiniz. Ancak, beforeTest başka bir String örneğine başvurduğundan, değiştirilmemiştir.

Kesintisizlik, alanları bir nesneye özel tutarak ve bu özel durumu değiştirmek için herhangi bir yöntem sağlayarak gerçekleştirilir. Yansıma kullanarak, tüm kapsülleme kurallarını kırarsınız ve böylece değişmezliği ihlal edebilirsiniz.

+0

Üçüncü örnek (test referansı) yeni örneğe de işaret etmiyor mu? Eğer "Orjinal" değişmez char "Değiştirilmiş" ile değiştirilirse daha önce test edilmemelidir Test değeri güncellenmelidir (çünkü aynı gerçek örnek de iletilmiş olabilir)? – kosa

+0

"Test" değişkeni "Orijinal" Dize değişmezinin bir kopyası için başlatıldı. Ancak, kopya oluşturulduğunda içeriğinin "Değiştirilmiş" olarak değiştirildiğini öğrendiniz. Yani "Değiştirilmiş" bir kopyası. 'beforeTest' ayrıca" Orijinal "Dize değişmezinin bir kopyasıdır, ancak kopya, içeriğini değiştirmeden önce yapılmıştır. –

İlgili konular