参考文章: 美团技术团队《深入解析String#intern》
关于String#intern()的几个知识点
-
jdk1.6和之后的HotSpot的差异
jdk1.6
将字符串常量池放在堆的Perm(永久区)中,Perm是和堆完全隔离的区域,所以这种情况下,String#intern()和new String()得到的是两个不同空间的对象,自然也就不相同了。另外Perm的大小是有限的,默认只有4M。
jdk1.7及以后
字符串常量池已经从 Perm 区移到正常的 Java Heap 区域了。为什么要移动,Perm 区域太小是一个主要原因,当然据消息称 jdk8 已经直接取消了 Perm 区域,而新建立了一个元区域。应该是 jdk 开发者认为 Perm 区域已经不适合现在 JAVA 的发展了。
在jdk1.7中调用String#intern()方法,执行的步骤如下
-
先查询字符串常量池是否存在和当前内容一致的字符串,有就直接返回该字符串。
-
如果字符串常量池中没有就去堆中查找,此时又有两种结果:
-
堆中有对应的对象,此时就在字符串常量池中保存该对象的引用,并返回该引用
-
堆中没有对应的对象,则在字符串常量池中创建对象,并返回其引用。
-
所以,一共会存在三种情况,但仔细想一下,因为String#intern()是一个实例方法,所以上面
12
这种情况是不会发生的,也就是说其实只有两种情况。 -
-
new String()创建的对象会将对象同时放入字符串常量池,这时1.6和1.7的做法各不一样,1.6是复制一份到字符串常量池中,而1.7是在常量池中保留一份该对象在堆中的引用地址(当然前提是该对象第一次执行这个inter()操作滴时候)
-
通过双引号直接创建的字符串对象, 在第一次被使用到时(如
String str="abbds" 或者 "abbds".equals(xxx))
)会直接将对象存入字符串常量池中。这是再有相同内容的String#intern()
方法,就会直接返回字符串常量池中该对象滴引用