String的intern方法在jdk1.6与jdk1.7之间的区别

最近看到这种类型的面试题,十分不解,就对此做了一些研究,现记录一下学习成果,待自己以后回顾查阅:

首选确定一下intern方法的功能

/** 
 * 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™ 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. 
 */ 

以上是源码中的注解,我简单解释一下,intern的方法返回字符串对象的规范表示形式。其中它做的事情是:首先去判断该字符串是否在常量池中存在,如果存在返回常量池中的字符串(为了好理解,我觉得可以认为是常量池中的地址),如果在常量池中不存在,先在常量池中添加该字符串,然后返回在堆中的引用地址,jdk1.6和jdk1.7中该方法的功能是一致的,不同的是常量池位置的改变(jdk1.7将常量池放在了堆空间中),下面具体说明。

第一种情况:

String s1 = new String("1");
s1.intern();
String s2 = "1";
System.out.println(s1 == s2);

jdk1.6和jdk1.7的运行结果均为false

这种情况中第一行代码做的事情是:在栈中开辟空间存储s1(指向堆中引用地址)、在常量池中添加"1"、在堆中开辟空间存储对象引用;第二行的s1.intern(),首先去常量池查找,发现有该常量,则返回常量池中的字符串(注意这里并没有使用该返回值),第三行中,在栈中开辟空间存储s2,s2发现常量池中已经有了"1",则直接指向该常量,所以s1和s2一定不等。

第二种情况:

String s1 = new String("1");
System.out.println(s1.intern() == s1);

jdk1.6和jdk1.7的运行结果均为false

这种情况与第一种情况的区别在于是拿s1.intern()的返回值与s1比较,由上述可知s1.intern()返回的是常量池中的字符串,s1指向的是堆中的引用地址,所以二者不想等。

第三种情况:

String s1 = new String("1") + new String("1");
s1.intern();
String s2 = "11";
System.out.println(s1 == s2);

jdk1.6运行结果是false,jdk1.7运行结果是true

第一行代码做的事情(只说对我们有影响的):在栈中开辟空间存储s1(指向堆中引用地址)、在堆中开辟空间存储对象引用("11"),接下来是jdk1.6和jdk1.7之间的区别:

jdk1.6中,s1.intern()运行时,首先去常量池查找,发现没有该常量,则在常量池中开辟空间存储"11",返回常量池中的值(注意这里也没有使用该返回值),第三行中,s2则使栈中空间直接指向常量池,所以s1和s2不相等。

jdk1.7中,由于常量池在堆空间中,所以在s1.intern()运行时,发现常量池没有常量,则添加常量并使其指向堆空间地址,返回堆空间地址(注意这里也没有使用该返回值),这时s2通过查找常量池中的常量,同样也指向了堆空间地址,所以s1和s2相等。

第四种情况:

String s1 = new String("1") + new String("1");
System.out.println(s1.intern() == s1);

jdk1.6运行结果是false,jdk1.7运行结果是true,接下来我们分别说明流程

这种情况与第三种情况的区别在于是拿s1.intern()的返回值与s1比较

 

jdk1.6中,常量池在Perm区中,s1.intern()去常量池中查找"11",发现没有该常量,则在常量池中开辟空间存储"11",返回常量池中的值,s1指向堆空间地址,所以二者不相等。

jdk1.7中,常量池在堆空间,s1.intern()去常量池中查找"11",发现没有该常量,则在常量池中开辟空间,指向堆空间地址,则返回常量池指向的堆空间地址,s1也是堆空间地址,所以二者相等。

总结

这种类型题主要考察的知识点有:

1、intern(本地化)的动作:常量池中存在和常量池中不存在

2、jdk1.6和jdk1.7中常量池的位置

3、intern的返回值是什么

4、比较对象是哪些

 

感谢@我想静静525的指出,我又重新审视了自己的思路和说辞,第四种方法的确是错了,完全和上面反了,以后还是要仔细些啊!

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值