Java--深入理解字符串的String#intern()方法奥妙之处_intern java string 解释

先自我介绍一下,小编浙江大学毕业,去过华为、字节跳动等大厂,目前阿里P7

深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年最新网络安全全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。
img
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上网络安全知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以添加V获取:vip204888 (备注网络安全)
img

正文


先来执行一下String调用intern()方法的一段示例代码:

public class StringInternTest {
    public static void main(String[] args) {
        String reference1 = new String("a");
        reference1.intern();
        String reference2 = "a";
        System.out.println(reference1 == reference2);

        String reference3 = new String("a") + new String("a");
        reference3.intern();
        String reference4 = "aa";
        System.out.println(reference3 == reference4);
    }
}

JDK1.6 执行输出结果:

false
false

JDK1.7 执行输出结果:

false
true

大家可以先思考一下为什么结果是这样的?往下会具体介绍!

String##intern()源码


先来看一下intern()方法的JDK源码如下:


    /\*\*
 \* Returns a canonical representation for the string object.
 \* <p>
 \* A pool of strings, initially empty, is maintained privately by the
 \* class {@code String}.
 \* <p>
 \* When the intern method is invoked, if the pool already contains a
 \* string equal to this {@code String} object as determined by
 \* the {@link #equals(Object)} method, then the string from the pool is
 \* returned. Otherwise, this {@code String} object is added to the
 \* pool and a reference to this {@code String} object is returned.
 \* <p>
 \* It follows that for any two strings {@code s} and {@code t},
 \* {@code s.intern() == t.intern()} is {@code true}
 \* if and only if {@code s.equals(t)} is {@code true}.
 \* <p>
 \* All literal strings and string-valued constant expressions are
 \* interned. String literals are defined in section 3.10.5 of the
 \* <cite>The Java&trade; Language Specification</cite>.
 \*
 \* @return a string that has the same contents as this string, but is
 \* guaranteed to be from a pool of unique strings.
 \*/
    public native String intern();

很显然通过源码可以看到intern()是一个native本地方法,但是native具体实现源码已经被隐藏了,这是一个历史故事了,SUN公司在JDK7开发期间,由于技术竞争和商业竞争陷入泥潭,无力再投入精力继续研发JDK,Oracle半路杀出直接收购Sun公司,Oracle接管JDK的研发后,发版了自己的Oracle JDK,Oracle的native底层等很多源码就被隐藏了,不过Oracle官方也声明OpenJDK和Oracle JDK7及以后版本,源码几乎是一模一样的,想要了解native底层源码具体实现过程,可以下载开源的OpenJDK的源码进行查看。

OpenJDK官网:https://hg.openjdk.java.net/
GitHub也开源啦:https://github.com/openjdk/jdk

例如String对应的OpenJDK底层源码主入口:jdk7\jdk\src\share\native\java\lang\String.c

Java\_java\_lang\_String\_intern(JNIEnv \*env, jobject this)
{
    return JVM\_InternString(env, this);
}

native底层方法的实现,需要掌握C和C++的语法,学习门槛要求比较高,这里不是我们要学习的重点,不做具体介绍。

String#intern()方法作用


前面JDK源码intern()方法的英文注释已经说明了intern()方法的有具体用途了,网上也有很多说明,不过这里我以个人的理解以及话术简单概括下intern()方法的作用如下:

(1)只要调用String对象的intern(),都会去找到字符串常量池,然后判断String对象的字符串内容是否已经存在常量池中,不存在,则往字符串常量池中创建该字符串内容的对象(JDK6及之前)或创建新的引用并指向堆区已有对象地址(JDK7之后),存在则直接返回。

(2)JDK7时,字符串常量池从永久代脱离,迁移到堆区中,相比于JDK6,变化不只是字符串常量池迁移到堆区而已,另一个变化就是调用字符串对象的intern()方法,如果字符串常量池中不存在该字符串内容的对象,则不会再像JDK6直接往字符串常量池中创建该字符串内容的对象,而是创建一个新的引用并指向堆区已有对象地址,实现字符串常量池和堆区字符串共用的目的,效率更高。

JDK6 String#intern()执行说明

一张图介绍前面示例代码JDK6执行过程如下:
在这里插入图片描述

/\*\*
 \* JDK6 String#intern()执行说明
 \*/
public class StringInternTest {
    public static void main(String[] args) {
        //Step6.1
        //创建了2个对象,分别是堆区的String对象和字符串常量池中的"a"对象,reference1引用指向在堆区中的对象地址
        String reference1 = new String("a");
        //Step6.2
        //判断字符串常量池,是否该字符串"a",此前,池中已经有该对象了,因此会返回池中的对象地址的引用
        reference1.intern();
        //Step6.3
        //字符串常量池中已存在字符串"a",因此reference2引用直接指向对象在字符串常量池中的地址
        String reference2 = "a";
        //reference1指向对象地址是在堆区,reference2指向对象地址是在永久代的常量池,显然不可能一样
        System.out.println(reference1 == reference2);

        //Step6.4
        //创建了2个对象,分别是在堆区的String对象(内容是"aa")和字符串常量池中的"a"对象
        //reference3引用指向对象在堆区中的地址,这过程还会在堆区创建了两个无引用的"a"对象,这里不做讨论
        String reference3 = new String("a") + new String("a");
        //Step6.5
        //判断永久代中的字符串常量池,是否存在该字符串"aa",这里是首次出现,因此直接将字符串拷贝并放到池中
        reference3.intern();
        //Step6.6
        //池中已存在该字符串,reference2引用直接指向对象在永久代字符串常量池中的地址
        String reference4 = "aa";
        //同样,reference3指向堆区地址,reference4指向永久代常量池中的地址,显然不可能一样
        System.out.println(reference3 == reference4);
    }
}

JDK7 String#intern()执行说明

一张图介绍前面示例代码JDK7执行过程如下:
在这里插入图片描述

/\*\*
 \* JDK1.7 String#intern()执行说明
 \*\*/
public class StringInternTest {
    public static void main(String[] args) {
        //Step7.1
        //创建了2个对象,分别是堆区的String对象和字符串常量池中的"a"对象,reference1引用指向在堆区中的对象地址
        String reference1 = new String("a");
        //Step7.2
        //判断字符串常量池,是否该字符串"a",此前,池中已经有该对象了,因此会返回池中的对象地址的引用
        reference1.intern();
        //Step7.3
        //字符串常量池中已存在字符串"a",因此reference2引用直接指向对象在字符串常量池中的地址
        String reference2 = "a";
        //reference1指向对象地址是在堆区,reference2指向对象地址是在堆区的字符串常量池,引用指向的对象地址不一样
        System.out.println( reference1 == reference2);

        //Step7.4
        //创建了2个对象,分别是在堆区的String对象(内容是"aa")和字符串常量池中的"a"对象(注意并不会创建"aa"对象)
        //reference3引用指向对象在堆区中的地址,这过程还会在堆区创建了两个无引用的"a"对象,这里不做讨论
        String reference3 = new String("a") + new String("a");
        //Step7.5


## 学习路线:

这个方向初期比较容易入门一些,掌握一些基本技术,拿起各种现成的工具就可以开黑了。不过,要想从脚本小子变成黑客大神,这个方向越往后,需要学习和掌握的东西就会越来越多以下是网络渗透需要学习的内容:  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/7a04c5d629f1415a9e35662316578e07.png#pic_center)





**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**

**需要这份系统化的资料的朋友,可以添加V获取:vip204888 (备注网络安全)**
![img](https://img-blog.csdnimg.cn/img_convert/3d93bf573dd520eb8f0f495976567f8d.png)

**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**

大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**

**需要这份系统化的资料的朋友,可以添加V获取:vip204888 (备注网络安全)**
[外链图片转存中...(img-pk43sHPY-1713333683661)]

**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**

  • 12
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值