String 的 intern() 方法解析

一、概述

JDK7 之前和之后的版本,String 的 intern() 方法在实现上存在差异,本文的说明环境是 JDK8,会在文末说明 intern() 方法的版本差异性。

intern() 方法是一个 native 的方法,返回常量池中的字符串引用,主要体现在以下两点:

  1. 如果常量池中已存在该字符串,则直接返回常量池中该对象的引用。
  2. 如果常量池中不存在该字符串,则在常量池中加入该对象引用并返回。

二、示例说明

一般我们创建字符串的方式有以下三种:

  1. 字面量创建方式,例如 String s = "java"
  2. new String() 创建方式,例如 String s = new String("java")
  3. StringBuilder/StringBuffer 创建方式,例如 String s = new StringBuilder("ja").append("va").toString()

字面量创建方式,会在字符串常量池中创建字符串实例,并返回该引用;new String() 和 StringBuilder/StringBuffer 创建方式都是在堆(Heap)上创建字符串实例,并返回该引用。

public class StrIntrenTest {
    
    public static void main(String[] args) {
        // 1. 字面量创建形式
        String s1 = "jmcui";
        //  1. 在字符串常量池中生成字符串【"jmcui"】实例
        //  2. 将栈中的 s1 指向字符串常量池中的字符串【"jmcui"】实例

        System.out.println("s1 == s1.intern() :" + (s1 == s1.intern())); // true

        // 2. new 创建方式
        String s2 = new String("jmcui");
        //  1. 在Java堆中生成字符串【"jmcui"】实例
        //  2. 将栈中的 s2 指向Java堆中的字符串【"jmcui"】实例

        System.out.println("s1 == s2 :" + (s1 == s2)); // false
        System.out.println("s1.equals(s2) :" + s1.equals(s2)); // true
        System.out.println("s1 == s2.intern():" + (s1 == s2.intern())); // true

        // 3. StringBuilder/StringBuffer 方式和 new 方法类似
        String s3 = new StringBuilder("jm").append("cui").toString();
        //  1. 在Java堆中生成字符串【"jmcui"】实例
        //  2. 将栈中的 s3 指向Java堆中的字符串【"jmcui"】实例
        System.out.println("s1 == s3 :" + (s1 == s3)); // false
        System.out.println("s2 == s3 :" + (s2 == s3)); // false
        System.out.println("s2.intern() == s3.intern() :" + (s2.intern() == s3.intern())); // true
    }
}
  • s1 == s1.intern() 返回 true,因为字面量的创建方式是在字符串常量池中生成实例,而 intern() 方法返回常量池中的字符串引用,两个引用自然是同一个。
  • s1 == s2 返回 false,因为 new String() 的方式是在堆(Heap)上创建实例,二者不是同一个引用。
  • s1.equals(s2) 返回 true,equals 方法是用来比较的是两个字符串的内容是否相等。
  • s1 == s2.intern() 返回 true,当 s2 调用 intern() 方法的时候,发现常量池中已经存在该字符串,则直接返回了该引用(s1 的引用)。
  • s1 == s3 返回 false, StringBuilder/StringBuffer 创建方式是在堆(Heap)上创建字符串实例,二者不是同一个引用。
  • s2 == s3 返回 fasle,s2 和 s3 都是 new 出来的字符串实例,在堆(Heap)上存储不同的位置,自然不是同一个实例。
  • s2.intern() == s3.intern() 返回 true,前面说明 s2 的 intern() 返回的是 s1 的引用,s3 的 intern() 也是一样的道理,因此 s2 的 intern() 和 s2 的 intern() 返回的都是 s1 的引用,所以相等。

三、和 JDK6 的版本差异

JDK7 之后的 intern() 方法和之前版本的差异主要体现在:如果常量池中不存在该字符串时的处理机制。

JDK7 之后的版本,如果常量池中不存在该字符串,则在常量池中加入该对象引用并返回。注意,关键词 — 加入对象引用!

JDK7 之前的版本呢?它的处理机制是,如果常量池中不存在该字符串,则在常量池中新建一个字符串实例并返回该实例引用。关键词:新建实例!

posted @   JMCui  阅读(639)  评论(0编辑  收藏  举报
编辑推荐:
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
历史上的今天:
2018-11-14 装饰者模式.
点击右上角即可分享
微信分享提示