字符串字面量赋值优先复用常量池对象,==可能为true;new String()强制堆中新建对象,==必为false;字符/字节数组构造需显式指定编码;拼接应使用StringBuilder再toString。

字符串字面量直接赋值最常用,但要注意内存复用机制
Java 中最简洁的字符串定义方式是用双引号写死内容,例如 "hello"。这种写法会优先在字符串常量池中查找是否存在相同内容,若存在则复用已有对象,否则新建并入池。这意味着两个字面量相同的 String 变量,用 == 比较可能返回 true(如 String a = "abc"; String b = "abc";),但这仅限于编译期确定的字面量。
- 运行时拼接(如
"ab" + new String("c"))不会自动入池,==判断大概率为false - 想强制入池,得显式调用
.intern()方法 - 字面量方式无法动态构造内容,不适合从用户输入、文件或网络读取的场景
用 new String() 构造器创建新对象,绕过常量池复用
写成 new String("hello") 会在堆上新建一个 String 实例,即使常量池中已有相同内容。此时该对象与字面量对象地址不同,== 一定为 false,必须用 .equals() 判断内容相等。
- 多数情况下没必要用
new String("..."),纯属浪费内存和 GC 压力 - 极少数需要确保对象唯一性(比如做锁对象、测试引用隔离)时才考虑
- 注意
new String(null)会抛出NullPointerException,而new String((String)null)编译不通过
从字符数组、字节数组初始化字符串需留意编码和范围
当数据来源是 char[] 或 byte[](比如解析协议、读取二进制流),要用对应构造器:new String(charArr)、new String(byteArr, "UTF-8") 等。编码参数不传默认用平台默认编码,跨环境极易出乱码。
-
new String(byteArr)不指定编码时行为不可控,生产代码必须显式传编码名 - 用
new String(byteArr, offset, length, charset)可避免复制整个大数组,适合处理部分数据 -
char[]构造器不会拷贝数组,后续修改原数组会影响字符串内容(JDK 9+ 已修复,内部改用byte[]存储,但语义上仍建议视为只读)
StringBuilder / StringBuffer 转 String 是拼接后的最终落点
大量字符串拼接(尤其循环中)别用 +,应先用 StringBuilder(单线程)或 StringBuffer(线程安全)累积,最后调用 .toString() 得到不可变 String 实例。这个 toString() 方法返回的是新创建的字符串对象,内容与当前 builder 内容一致,但独立于 builder 的后续修改。
立即学习“Java免费学习笔记(深入)”;
-
StringBuilder.toString()在 JDK 7u6 之后做了优化,若内部char[]未被共享,会直接复用数组内容,减少一次拷贝 - 不要反复调用
builder.toString(),每次都会新建对象;拼完一次就存下来 -
StringBuffer的同步开销在多数 Web 场景下无必要,除非明确多线程共用同一实例
String 类设计保证的;所有看似修改的操作(如 substring、replace)都返回新对象。真正容易忽略的是常量池行为对 == 的影响,以及字节数组构造时编码缺失导致的隐性 bug。









