编程Java开发人员

描述Java中字符串的特点,以及如何使用String/StringBuilder/StringBuffer,何时使用它们以及使用时可能遇到的陷阱是什么?

用 Hintsage AI 助手通过面试

回答。

在Java中,String类是immutable(不可变的):任何修改操作都会创建一个新对象。StringBuilderStringBuffer类是可变的,用于循环内的连接和复杂转换。

关键区别:

  • String:不可变,线程安全,无需额外同步。适合可读的、不变的文本(例如,密钥、消息)。
  • StringBuilder:可变,不线程安全,但连接速度快。用于字符串多次变化的场景。
  • StringBuffer:可变,线程安全(方法已同步),但在性能上不如StringBuilder

速度比较示例:

String s = ""; for (int i = 0; i < 10000; i++) { s += i; // 每次都会创建新的String,很慢! } // 更好的方式: StringBuilder sb = new StringBuilder(); for (int i = 0; i < 10000; i++) { sb.append(i); } String result = sb.toString();

潜在问题:

  • 过度连接不可变字符串可能导致内存泄漏和性能下降。
  • String.intern()可能在有大量唯一字符串时引发OutOfMemoryError,尤其在PermGen/Metaspace中。
  • 在多线程场景中错误使用StringBuilder可能导致竞争条件。

难题。

问题: "在循环内使用"+"操作符连接字符串是否有效?"

回答: 不,每次都会创建新的String对象,这会大量占用内存并负担GC。对于许多操作,最好使用StringBuilderStringBuffer(如果需要线程安全)。

示例:

String s = ""; for (int i = 0; i < 1000; i++) { s += i; // 非常低效! } // vs StringBuilder sb = new StringBuilder(); for (int i = 0; i < 1000; i++) { sb.append(i); }

因为不了解主题的细节而导致的真实错误示例。


故事

在一个银行项目中,用"+"运算符在大循环中连接字符串使得夜间分析速度降低了15倍。通过替换为StringBuilder解决了这个问题,执行时间从40分钟缩短到2分钟。


故事

一位年轻开发人员对线程使用不当,在同一个外观对象中使用StringBuilder,该对象被多个线程同时访问。这导致了随机的错误和不正确的结果,因为缺乏同步。


故事

在一个项目中,通过String.intern()创建唯一标签。当用户数量达到数千万时,JVM抛出了OutOfMemoryError: PermGen space。通过放弃使用intern()并转向其他缓存机制解决了问题。