在Java中可变字符串(Mutable strings in Java)

2019-07-30 01:43发布

由于几乎每个人都知道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);

输出将是:

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

请问这个伎俩工作? 如何在JVM知道哪些对象应该被改变,并且不是? 此招的引擎盖下有什么机制? 为什么已经创建beforeTest字符串没有改变? 这是否招果然减损的strings are immutable的原则?

Answer 1:

字符串字面被拘禁到池中。 这意味着,当你写

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

S1和S2是指相同的字符串对象,和s3是指另一个,被另一个字符数组支持。

在代码中,你通过修改私人字符数组抱着“原始”字符串文字实例的字符字符串违反的不变量。 但由于beforeTest是指另一个String实例,它不会被修改。

不变性通过保持字段私人到一个对象,而不是提供来修改该私有状态的任何方法来实现。 通过使用反射,你打破封装的所有规则,从而可以违反不变性。



文章来源: Mutable strings in Java