Java面试必问:字符串为什么不可变?源码+实例一次性讲透
🔥 面试官:String 为什么是不可变的?
📌 先看源码:String 不可变的核心设计
// 1. 类被 final 修饰 → 不能被继承public final class Stringimplements java.io.Serializable, Comparable// 2. 存储字符串的字符数组:private + finalprivate final char value[];// 哈希值缓存(后面会讲作用)private int hash; // Default to 0// 构造方法:初始化字符数组public String(String original) {this.value = original.value;this.hash = original.hash;}}
-
类被 final 修饰:String 不能被继承,子类没法重写方法篡改逻辑; -
char 数组 private + final: -
private:外部不能直接操作这个数组(比如修改某个字符); -
final:数组的引用地址一旦确定,就不能指向新的数组。
🤔 为什么要设计成不可变?3 个关键原因
public class SecurityDemo {public static void main(String[] args) {String password = "yunyang_123456"; // 原始密码checkPassword(password);System.out.println("最终密码:" + password); // 输出:yunyang_123456}private static void checkPassword(String pwd) {// 看似修改,实则创建新对象pwd = pwd.replace("123456", "xxxxxx");}}
public class HashDemo {public static void main(String[] args) {String s1 = "abc";String s2 = "abc";// 相同内容的字符串,哈希值相同且复用缓存System.out.println(s1.hashCode()); // 96354System.out.println(s2.hashCode()); // 96354(直接用缓存,不重复计算)// 新对象重新计算哈希值String s3 = new String("abc");System.out.println(s3.hashCode()); // 96354(内容相同,哈希值也相同)}}
public class ConstantPoolDemo {public static void main(String[] args) {String a = "hello"; // 从常量池获取(无则创建)String b = "hello"; // 共享 a 的引用String c = new String("hello"); // 新建对象,不进常量池System.out.println(a == b); // true(同一对象)System.out.println(a == c); // false(不同对象)System.out.println(a.equals(c)); // true(内容相同)}}
⚠️ 易错点:String 的 “修改” 其实是创建新对象
public classModifyDemo{public static void main(String[] args) {String original = "hello world";// 1. 截取 substring()String sub = original.substring(6);System.out.println("原字符串:" + original); // hello world(不变)System.out.println("截取后:" + sub); // world(新对象)// 2. 拼接 concat()String concat = original.concat("!");System.out.println("原字符串:" + original); // hello world(不变)System.out.println("拼接后:" + concat); // hello world!(新对象)}}
📝 实用技巧:频繁修改字符串用什么?
// 不推荐:循环中用 String 拼接(创建大量临时对象)String str = "";for (int i = 0; i 00; i++) {str += i;}// 推荐:用 StringBuilder 拼接StringBuilder sb = new StringBuilder();for (int i = 0; i < 1000; i++) {sb.append(i);}String result = sb.toString();
🌟 总结
-
底层依赖「final 类 + final 字符数组」; -
带来 3 大好处:安全(防篡改)、高效(缓存哈希)、省内存(常量池); -
易错点:“修改” 其实是新建对象,频繁修改用 StringBuilder/StringBuffer。
夜雨聆风