← 每日面试题 学习看板

String的设计,用到了哪些设计模式?

面试题/02架构设计题/09设计模式/String的设计,用到了哪些设计模式?.md

面试记录 2026-09-26

题目:String 的设计,用到了哪些设计模式?

难度:high

标签:arch/design-pattern, general/knowledge

评分:⭐☆☆☆☆

我的回答

String 用到的设计模式我没什么印象,那么我们来分析下 string 的特性来推导下,首先 string 的第一个特性是不可变,另外 string 还有常量的特性,创建出来但不可变队形会被放入常量空间进行复用;string 对象自身是通过 byte 数组或者 char 数组实现的,在不同的jdk 版本中;所有 string 对象都已一种模式的方法,那么是否算模板方法模式?

点评

优点:主动推导分析(没有直接放弃),提到不可变、常量池、字节数组实现、JDK 版本差异

严重不足:未识别享元模式(String 最经典的设计模式);误判模板方法模式;未说不可变模式(final class + final 字段 + 无 setter);未说代理模式(StringBuilder 作为可变代理、JDK 9+ 内部 StringLatin1/StringUTF16 代理存储);未说 String 不可变的四个好处

补充:三大模式——享元(常量池复用)、不可变(线程安全+哈希稳定)、代理(StringBuilder+JDK9 内部存储)

完整讲解

第一部分:知识重点剖析

核心考点定位:能否识别出 String 里的享元模式(最核心)、不可变模式、代理模式,并理解它们的设计动机。

知识点拆解:

  1. 享元模式(Flyweight)—— String 最经典的设计模式:
  1. 不可变模式(Immutable Object Pattern):
  1. 代理模式(Proxy):
  1. 为什么 String 要设计成不可变?(延伸理解)
  1. String 常见陷阱:
按「底层原理 → 设计权衡 → 工程实践」递进排列。

第二部分:考察方向与延伸递进

考察方向:

延伸递进面试题:

  1. "a" 和 new String("a") 是同一个对象吗?调 intern() 后呢?
  1. String 不可变有什么好处和代价?
  1. String 内部 JDK 9+ 为什么改成 byte[] + coder 字段?

第三部分:面试者参考回答(300-600 字口语化)

面试官您好,String 的设计主要用到三个设计模式:享元模式、不可变模式、代理模式。

第一个是享元模式,这是 String 最经典的设计。享元的核心思想是"相同对象共享"。在 String 里的体现就是字符串常量池:字面量 "hello" 会自动放入常量池,第二次写 "hello" 直接复用同一个对象。效果就是 "hello" == "hello" 为 true,多个变量引用同一个对象,节省大量内存。除了字面量入池,还有 s.intern() 手动入池——new String("hello").intern() 会返回常量池里的引用。

第二个是不可变模式(Immutable Object Pattern)。String 是不可变对象,体现在:类是 public final 不能继承;底层 private final byte[] value 字段不可变;没有 setter,所有"修改"方法如 concat、substring、toUpperCase 都返回新对象;构造器还做防御性拷贝,防止外部修改内部数组。

不可变带来四个好处:

代价是每次修改都要新建对象,所以频繁拼字符串要用 StringBuilder。

第三个是代理模式。String 的不可变性催生了两类代理:

第一类是 StringBuilder/Buffer 作为可变代理——频繁修改字符串的场景,先用 StringBuilder 拼接,最后 toString() 转回不可变 String。

第二类是 JDK 9+ 的 StringLatin1 和 StringUTF16——String 内部用这两个紧凑存储类作为代理,通过 coder 字段区分 Latin1(1 字节)和 UTF16(2 字节)。JDK 8 用 char[] 每个字符固定 2 字节,JDK 9 改成 byte[] + coder,Latin1 字符场景内存减半。

还有一个常见陷阱:"a" 在常量池,new String("a") 在堆,两者引用不同,== 为 false;但调 intern() 后,如果常量池已有相同内容,就返回常量池的引用,== 变 true。

总结一句话:String 是"享元模式 + 不可变模式 + 代理模式"的典型组合,既节省内存,又保证了线程安全和哈希稳定性。

这就是我对 String 设计的理解。