享元模式通过分离内部状态(可共享、不可变)和外部状态(客户端传入),复用物理实例以降低内存占用;内部状态如字体、字号等在构造时固化,外部状态如坐标、选中态由调用时传入,工厂统一缓存并返回共享实例。

Java 中享元模式通过分离对象的内部状态(可共享、不可变)和外部状态(不可共享、由客户端动态传入),让多个逻辑对象复用同一个物理实例,从而显著减少内存占用。
核心机制:内部状态 + 外部状态
享元对象本身只保存不会变化的部分——比如字符的 Unicode 值、字体族名、字号、颜色等固定属性。这些构成内部状态,在构造时确定,之后绝不修改,因此可安全共享。
而位置坐标、显示层级、临时高亮标记等随使用场景变化的数据,属于外部状态,不存于享元对象内,而是由客户端在调用 display() 或 operation() 方法时传入。
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
- 内部状态示例:字符 'A' 的 font="SimSun"、size=14、color="#000000"
- 外部状态示例:该 'A' 在文档中位于 (x=120, y=85),或当前是否被选中
享元工厂统一管理对象池
享元工厂(FlyweightFactory)是关键枢纽,它内部维护一个缓存结构(如 ConcurrentHashMap 或 HashMap),以内部状态为 key 查找已有实例:
- 首次请求某组内部状态(如字符 'B' + "Arial" + 12 + "blue")时,工厂创建 ConcreteFlyweight 实例并缓存
- 后续相同请求直接返回已缓存对象,不再 new 新实例
- 工厂通常线程安全,适合高并发场景(如文本渲染、棋盘格批量绘制)
典型 Java 应用案例
真实项目中,享元模式常隐式存在:
- String 常量池:字面量 "hello" 多次出现,JVM 只保留一份;new String("hello") 则绕过池,但 intern() 可主动归池
- Integer 缓存:Integer.valueOf(-128 ~ 127) 返回缓存对象,避免重复创建;超出范围则 new 新对象
- 自定义场景:10 万字符的编辑器中,若每个字符都含完整样式+位置信息,内存飙升;改用享元后,仅需几十个享元实例 + 10 万个轻量外部上下文
使用前提与注意事项
享元不是万能优化,需满足几个条件才真正有效:
- 对象数量大,且大量具备相同/相似内部状态
- 内部状态必须不可变(final 字段 + 无 setter),否则共享会引发数据污染
- 外部状态提取合理,不能把本该共享的字段误判为外部状态
- 享元工厂的缓存开销(哈希表内存、查找时间)应小于节省的内存总量
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










