Java字符串intern()函数的一些问题及其讨论

106 阅读2分钟

1.jdk1.7及以前

在jdk1.7级以前的jdk版本中,s.intern()的操作执行流程是这样的。首先检查常量池中是否有s所表示的字符串。如果有的话,则直接返回在字符串常量池中的字符串的地址值。如果没有,则在字符串中创建一个,并返回这个地址。

2.jdk1.8及以后

在这个版本中相对于1.7以前的版本的不同之处主要是针对的以下这个情况

String test = new String("aa");
test.intern();

这个名为test的字符串,其实是存在于非字符串常量池所在的堆空间中的。如果是1.7之前的版本,会在字符串常量池中创建一个字符串“aa”,并返回这个字符串常量池中的地址。在1.8及以后的版本中做了一些空间上的节约,因为如果是前者的情况,显然整个堆空间中会有两个字符串“aa”, 有冗余数据。因此后者所做的优化是,在字符串常量池中加入的不再是字符串常量“aa”,而是test的指针。这个时候,就可以保证堆空间中真正意义上只有一份字符串常量。
以下是列举的一个例子

String aabb = new String("aa") + new String("bb");
aabb.intern();
String tpp = "aabb";
System.out.println(aabb == tpp);

显然,根据上面的解释,结果应该输出为true。因为在字符串常量池中,最开始根本就没有“aabb”这个字符串常量。

String aabb = "aa" + new String("bb");
String tt = "aabb";
aabb.intern();

String x = aabb.intern();
System.out.println(tt == x);

在这个代码块中,明确“aabb”这个常量是在常量池中的。因此aabb.intern()并没有做什么额外的动作。aabb.intern()就会返回字符串常量池中的地址。因此最后输出true。

3.特别强调一个问题

new String("aabb")和new String("aa") + new String("bb")的区别
前者相当于创建了一个对象,并且用字符串常量池中的“aabb”进行属性的填充,相当于触发了init方法。 后者是stringBuilder的一个append操作,常量池中没有“aabb”.

4.总结

调用intern()方法的作用是,检查字符串常量池中到底有没有对应的字符串常量,如果有,则返回。没有则在常量池中加入指针,并返回这个指针。这个指针就相当于字符串常量池中的字符串常量。