深度解析 intern 方法

本文详细探讨了Java中String类的intern()方法的工作原理,通过代码示例和Javap反编译解释了不同情况下intern()的返回结果。文章指出,intern()方法会检查字符串常量池,如果存在相等的字符串则返回常量池的引用,否则将字符串添加到常量池。此外,还分析了JDK1.6和1.8之间的差异,以及不同创建字符串方式对结果的影响。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

String 类的 intern 方法非常特殊,底层做了很多操作,面试中也经常被问到,本文将带大家深度剖析此方法。

在正式开始之前,需要你知道 String 内存布局:

变量始终存的都是地址,只是是堆中地址还是常量池地址的问题。JVM 规范说明:方法区逻辑上属于堆内存,具体放在哪以及是否做垃圾回收由具体实现决定。

有了上面的铺垫,下面开始正文。

一、 方法注释

无论是 1.6 还是 1.8 关于 intern 方法的注释都是一样的:

简单一句话:调用 intern 方法时,会首先到常量池中找具有相等值的对象,找到的话返回常量池的对象,否则将该对象加入常量池,并返回该对象的引用。

有个大概印象,下面通过代码来加深理解。

下面先看下面代码:

            String str1 = new String("计算机软件");
            String intern = str1.intern();
            System.out.println(str1 == intern);

返回的是 false,为什么呢,我们用 javap 生成汇编代码:

可以看到 new String 使用的字符串已经放入常量池里了, str1 指向的是堆里对象实例的地址(new 申请的堆空间),str1.intern 会首先到常量池检查是否有相等(equals)的字符串,很显然有, 返回该常量池中字符串对应的地址。

所以 str1 指向的是堆里的地址,str1.intern 返回的事常量池中的地址,因此返回 false。

很显然,下面代码中的结果就是 true, 因为都是常量池的地址。

            String str1 = "计算机软件";
            String intern = str1.intern();
            System.out.println(str1 == intern);

下面,我们把代码稍微修改下:

            String str1 = new StringBuilder("计算机").append("软件").toString();
            String intern = str1.intern();
            System.out.println(str1 == intern);

这个时候结果是 true。还是使用 javap 反编译:

 大家发现没有,连接后的字符串 “计算机软件”并没有加入到常量池中,仍然在堆中,因此 intern 会将该对象(引用)加入常量池,并返回常量池里的该引用。

所以 str1 和 str1.intern  指向的都是是堆里的地址,因此返回 true。

比较绕,我们再看下面的代码:

            String str = "计算机软件";
            String str1 = new StringBuilder("计算机").append("软件").toString();
            String intern = str1.intern();
            System.out.println(str == intern); // true  
            System.out.println(str1 == intern); // false
            System.out.println(str == str1);    // false

intern 方法调用时,常量池中已经存在  “计算机软件”(第一行代码),因此直接返回的常量池的地址,而 str1 指向的是堆里的地址。

换个顺序:

         
            String str1 = new StringBuilder("计算机").append("软件").toString();
            String intern = str1.intern();
            String str = "计算机软件";
            System.out.println(str == intern); // true  
            System.out.println(str1 == intern); // true
            System.out.println(str == str1);    // true

intern 方法调用时,常量池中并不存在  “计算机软件”,因此会将“计算机软件” 对应的引用地址(str1 地址)加入常量池,实际上是通过是以 hash 方式存储:hash(计算机软件)=  str1 指向地址。

执行到 str = "计算机软件" 时, 会到常量池的 hash 表里查询,发现已经存在,就直接返回了 str1 地址,因此这三个都是指向堆内存里的相同一块内存。

值得注意的是,如果上面的代码放在 jdk 1.6 执行时,返回的则是 true/false/false,原因就是 jdk1.6 在执行 intern 方法时,会将该字符串实例复制到常量池中(位于永久代),因此返回的也就是字符串常量的地址,和 str1 的堆内存地址不同!

本文结束,有不明白地欢迎讨论交流~


如果觉得还不错的话,关注、分享、在看(关注不失联~), 原创不易,且看且珍惜~

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

【非典型Coder】

赏个鸡腿吧

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值