商城首页欢迎来到中国正版软件门户

您的位置: 首页 > 文章列表 > 编程开发 > String.intern()方法详解:手动入池技巧

String.intern()方法详解:手动入池技巧

  发布于2026-02-14 阅读(0)

扫一扫,手机访问

String.intern() 返回常量池中已存在字符串的引用,内容相同即复用;若不存在则将当前字符串内容放入池并返回其引用,与是否为字面量无关。

详解Java中的String.intern()方法_手动将字符串放入常量池

String.intern() 什么时候会返回堆上对象的引用

它不总返回常量池里的“新”对象,而是返回池中已存在字符串的引用;如果不存在,才把当前字符串(注意:是当前 String 对象的字符内容)放入池,并返回该引用。关键在于“内容相同即复用”,和你调用的是不是字面量无关。

常见错误现象:"abc".intern() == "abc"true,但 new String("abc").intern() == new String("abc")false —— 因为右边是堆上新对象,左边是常量池引用,两者地址不同。

  • 使用场景:避免重复字符串占用内存(如解析大量 JSON 字段名、日志中的固定标签)
  • 参数差异:无参数,纯实例方法,对 null 调用会抛 NullPointerException
  • 性能影响:首次调用需查表+可能插入,有锁开销(JDK 7+ 改到堆上,但仍是同步操作)

JDK 6 和 JDK 7+ 的 intern() 行为差异

JDK 6 把字符串常量池放在永久代(PermGen),空间小且不可扩容;JDK 7 起移到 Java 堆,受 GC 管理,行为更可控。这意味着在 JDK 6 中滥用 intern() 容易触发 java.lang.OutOfMemoryError: PermGen space,而 JDK 7+ 更多是堆内存压力。

典型误判:以为 intern() 总能“省内存”,其实它只是把字符串从堆某处挪到常量池——如果原对象还被强引用着,反而多占一份。

  • 必须确认字符串生命周期:长期存活、高复用率的才适合 intern()
  • JDK 8u20+ 默认开启 -XX:+UseG1GC 后,常量池回收更积极,但依然不会回收仍被引用的 interned 字符串
  • 验证方式:用 jmap -histo:live <pid> 查看 java.lang.String 实例数,配合 jstat -gc <pid> 观察老年代变化

为什么 String.valueOf(x).intern() 不等于 x.toString().intern()

因为 String.valueOf(null) 返回的是字符串 "null",而 null.toString() 直接抛 NullPointerException。哪怕 x 是非 null 对象,valueOf 可能调用 toString(),但也可能走分支逻辑(比如 String.valueOf(char[]) 直接构造新字符串)。

容易踩的坑:用 intern() 做 key 归一化时,没统一入口,导致相同语义的字符串进了两次常量池。

  • 永远优先用 String.valueOf(x) 替代 x.toString() 做空安全转换
  • 若 x 是 Integer 等包装类,String.valueOf(42)42 + "" 都会生成新对象,再 intern() 才进池
  • 数字转字符串后 intern() 效果有限:除非大量重复数值(如状态码 "200""404"),否则性价比低

用 intern() 做字符串比较前,先问自己三个问题

它不是万能的“加速器”。很多场景下,用 equals()==(仅限确定是字面量或已 intern 过)更直接可靠。

  • 这个字符串是否真的会在整个应用生命周期里高频出现?(比如配置项 key、协议字段名)
  • 有没有其他线程同时调用 intern()?高并发下锁竞争会让它变慢
  • 你能否控制所有创建路径?一旦漏掉某个构造方式(比如用了 StringBuilder.toString() 却没 intern()),比较就会失效

最常被忽略的一点:常量池里的字符串,只要被任何地方强引用着,就不会被 GC;而堆上字符串可以随时回收。所以“省内存”是有代价的——换来的可能是更难排查的内存泄漏。

本文转载于:互联网 如有侵犯,请联系zhengruancom@outlook.com删除。
免责声明:正软商城发布此文仅为传递信息,不代表正软商城认同其观点或证实其描述。
  • using namespace 使用中遇到的问题怎么解决 正版软件
    using namespace 使用中遇到的问题怎么解决
    命名空间的基本概念与常见引入问题在C++等编程语言中,命名空间(namespace)是一种将代码标识符(如变量、函数、类名)封装在特定名称下的机制,其主要目的是避免命名冲突,尤其是在大型项目或使用多个第三方库时。使用“using namespace”指令可以将指定命名空间中的所有名称引入当前作用域,
    9天前 0
  • c语言函数递归 实操经验总结:这些技巧很实用 正版软件
    c语言函数递归 实操经验总结:这些技巧很实用
    理解递归的基本原理在C语言中,递归是一种函数调用自身的编程技术。要掌握它,首先需要理解其核心思想:将一个复杂的大问题,分解为一个或几个与原问题相似但规模更小的子问题,直到子问题足够简单,可以直接求解。这个过程通常包含两个关键部分:递归出口和递归体。递归出口定义了问题何时不再继续分解,即最简单、可直接
    9天前 0
  • c语言函数递归 怎么选?常见方案对比分析 正版软件
    c语言函数递归 怎么选?常见方案对比分析
    递归函数的基本概念与适用场景在C语言编程中,递归是一种函数调用自身的编程技巧。它并非适用于所有问题,但在处理某些具有自相似结构的问题时,能提供极其清晰和优雅的解决方案。递归的核心思想是将一个大规模问题分解为一个或多个同类型但规模更小的子问题,直到子问题简单到可以直接求解。典型的适用场景包括树形结构的
    9天前 0
  • Objective-C 内存管理入门:从 alloc 到 dealloc 的生命周期详解 正版软件
    Objective-C 内存管理入门:从 alloc 到 dealloc 的生命周期详解
    理解内存管理的基石在Objective-C的编程世界中,内存管理是开发者必须掌握的核心技能之一。它直接关系到应用的性能、稳定性与资源利用效率。与一些采用自动垃圾回收机制的语言不同,Objective-C在很长一段时间里,依赖一套基于引用计数的、需要开发者部分介入的管理规则。这套规则的核心思想是明确的
    9天前 0
  • 如何正确使用 dealloc 以避免 iOS 应用中的内存泄漏 正版软件
    如何正确使用 dealloc 以避免 iOS 应用中的内存泄漏
    理解 dealloc 的角色与时机在 iOS 应用开发中,内存管理是保障应用性能与稳定性的基石。dealloc 方法是 Objective-C 中对象生命周期结束时的关键回调,它标志着对象即将被系统回收内存。正确理解其触发时机至关重要:当一个对象的引用计数降为零时,运行时系统会自动调用该对象的 de
    9天前 0