java - Java 中的可变字符串

标签 java string reflection

几乎每个人都知道 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 原则吗?

最佳答案

字符串文字被驻留在池中。这意味着当你写

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

s1 和 s2 指的是同一个 String 对象,而 s3 指的是另一个,由另一个 char 数组支持。

在您的代码中,您通过修改包含“原始”字符串文字实例的字符的私有(private)字符数组违反了字符串的不变量。但是由于 beforeTest 引用了另一个 String 实例,所以它没有被修改。

不变性是通过将字段保持为对象的私有(private)状态而不提供任何方法来修改此私有(private)状态来实现的。通过使用反射,您打破了所有封装规则,因此您可以违反不变性。

关于java - Java 中的可变字符串,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11164675/

相关文章:

java - AAPT:错误:找不到属性 android:clipToOutline

java - 从 JAXB 迁移到 Castor 的简单方法?

java - 我们如何递归列出所有文件和文件夹?

列表中字符串的python模式切割

C# 将 Dictionary<string, AnyType> 转换为 Dictionary<string, Object> (涉及反射)

C# EF 必需属性无法识别

java - 如何让扫描仪读取文件中的下一行?

sql - 在SQL中将字符串列表转换为Int列表

c - 如何将十六进制字符缓冲区转换为 ASCII 字符串 [C]

java - 如何使用反射获取注释类名称、属性值