前言
面试的时候经常被问到String的intern方法的调用及内存结构发生的变化。但在实际生产中真正用到过了吗,看到过别人如何使用了吗?
最近阅读Nacos的源码,还真看到代码中使用String类的intern方法,NamingUtils类中有这样一个方法:
- public static String getGroupedName(final String serviceName, final String groupName) {
- // …省略参数校验部分
- final String resultGroupedName = groupName + Constants.SERVICE_INFO_SPLITER + serviceName;
- return resultGroupedName.intern();
- }
方法操作很简单,就是拼接一个GrouedName的字符串,但为什么在最后调用了一下intern方法呢?本篇文章我们就来分析一下。
intern方法的基本定义
先来看一下String中intern方法的定义:
- public native String intern();
发现是native的方法,暂时我们无法更进一步看到它的具体实现。很多朋友至此便浅尝辄止了,其实我们还可以通过文档说明及一些工具来验证intern方法的作用及运作原理。
在intern方法上有一段注释来介绍它的功能,大意是:当调用intern方法时,如果字符串常量池中不存在对应的字符串(通过equals方法比较),则将该字符串添加到常量池中;如果存在则直接返回对应地址。
我们都知道字符串常量池的功能类似缓存,它可以让程序在运行的过程中速度更快、更节省内存。而上述代码之所以调用intern方法想必便是为了此目的。
字符串及常量池内存结构
要了解intern的作用,不得不先了解一下String字符串的内存结构。
字符串的创建通常有两种形式,通过new关键字创建和通过引号直接赋值的形式。这两种形式的字符串创建在内存分布上是有区别的。
直接使用双引号创建字符串时,会先去常量池查找该字符串是否已经存在,如果不存在的话先在常量池创建常量对象,然后返回引用地址;如果存在,则直接返回。