目录
1. 字符数组的私有性和不可变性
2. 没有提供修改内容的方法
3. 共享字符串常量池
4.不可变性的优点
5.结论
🎈边走、边悟🎈迟早会好 |
Java 中的 String
对象是不可变的。不可变性意味着一旦创建了一个 String
对象,它的值就不能再被改变。这一特性在 Java 中是通过以下方式实现的:
1. 字符数组的私有性和不可变性
String
类在内部使用一个字符数组来存储字符串的内容。这个字符数组是私有的,并且没有提供修改其内容的方法。
public final class String implements java.io.Serializable, Comparable<String>, CharSequence {
private final char value[];
...
}
由于 value
是 final
,所以一旦分配了数组引用,就不能再改变它指向的数组。但是注意,这并不阻止数组本身的内容被改变(假设能访问到这个数组)。不过,由于它是私有的,并且没有方法暴露它,外部是无法直接修改这个数组的内容。
2. 没有提供修改内容的方法
String
类没有提供任何方法来修改其内容。所有修改 String
对象的方法(例如 concat
、substring
、replace
等)都会返回一个新的 String
对象,而不会修改原来的对象。
String s = "Hello"; String t = s.replace('H', 'J');
// s 仍然是 "Hello",t 是 "Jello"
3. 共享字符串常量池
Java 通过字符串常量池来优化 String
对象的存储。当你创建一个字符串字面量时,Java 会先检查常量池中是否已经有一个相同值的字符串对象。如果有,则返回这个对象的引用;如果没有,则创建一个新的字符串对象并放入池中。这进一步增强了 String
对象的不可变性,因为同一个字符串字面量在 JVM 中只有一个实例。
String s1 = "Hello"; String s2 = "Hello";
System.out.println(s1 == s2); // 输出 true
4.不可变性的优点
- 线程安全:
String
对象是不可变的,因此可以在多个线程间安全地共享,不需要同步。 - 性能优化:由于字符串不可变,Java 可以安全地在字符串常量池中缓存和重用字符串。
- 安全性:不可变的字符串可以防止不小心或恶意修改,例如在使用字符串作为哈希表的键或在网络传输中。
5.结论
Java 的 String
对象确实是不可变的。这种不可变性是通过类设计、私有字段和缺乏修改方法来实现的,从而提供了许多线程安全性和性能方面的优势。如果需要可变的字符串,可以使用 StringBuilder
或 StringBuffer
类。
示例代码
public class StringImmutability {
public static void main(String[] args) {
String s1 = "Hello";
String s2 = "World";
// s1 和 s2 都是不可变的
String s3 = s1.concat(s2); // 生成新的字符串 "HelloWorld"
System.out.println("s1: " + s1); // 输出 "Hello"
System.out.println("s2: " + s2); // 输出 "World"
System.out.println("s3: " + s3); // 输出 "HelloWorld"
}
}
通过以上示例,可以看到 s1
和 s2
在调用 concat
方法后仍然保持原样,说明 String
对象是不可变的。
如果想强行改变,可以通过反射进行改变,但不推荐,因为违反了 Java 对 String 类的不可变设计原则,会造成一些安全问题
String str = "Hello tingyi";
System.out.println(str); // Hello tingyi
Field field = String.class.getDeclaredField("value");
field.setAccessible(true);
char[] value = (char[])field.get(str);
value[6] = 'J';
value[7] = 'a';
value[8] = 'v';
value[9] = 'a';
value[10] = '!';
value[11] = '!';
System.out.println(str); // Hello Java!!
🌟感谢支持 听忆.-CSDN博客
🎈众口难调🎈从心就好 |