Java面试题——String.intern()和字符串的==判定

前言

以1.7后的版本为例,String.intern():

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

这段是对intern()方法的源码注释,大概翻译为两点:

  1. intern()表示先在常量池中查询字符串是否存在,存在的依据是用equals()方法判断,相等则表示存在。如果存在(true),则返回该字符串(then the string from the pool is returned);
  2. 如果字符串不存在,则将该字符串对象添加到常量池中,并返回该字符串的引用(a reference to this object is returned)

案例分析

//	案例一
String s1 = new String("abc");
System.out.println(s1 == s1.intern());//false	

案例一分析:
new String(“abc”):做了2件事:

	 1. ""表示在常量池中开辟了一个地址,存入abc;
	 2. new String()表示在堆空间中开辟了一个地址,存入abc;
  • s1是堆空间地址,s1.intern()先判断常量池有没有"abc",发现有,ok直接返回该地址,因此s1.intern()是常量池的地址
// 案例二
String s1 = new String("a") + new String("bc");
System.out.println(s1 == s1.intern());//true

案例二分析
new String(“a”) + new String(“bc”):做了3件事:
(篇幅有限,同一个空间创建算1件事)

	1.""表示常量池创建a,常量池创建bc;
	2. new String()堆空间创建a,堆空间创建bc
	3.+表示堆空间创建abc
  • 所以s1是堆空间地址,s1.intern()先去常量池找abc,没有,ok创建abc对象,返回该对象的引用。
  • 注意1.7后由于堆已有abc,所以创建abc对象相当于将堆空间的地址拷贝一份到常量池中。
  • 因此,s1.intern()表示堆空间的地址
// 案例三
String s1 = new String("a") + "bc";
System.out.println(s1 == s1.intern());//true

案例三分析
根据案例二的分析,做了3件事

	1.字符串a在堆空间和常量池各创建一份,
	2.而bc很明显只有常量池创建,
	3.+则表示堆空间创建了abc
  • 因此,s1表示堆空间地址,s1.intern()发现常量池没有abc,则将堆空间地址拷贝一份到常量池,所以s1.intern()表示堆空间的地址
// 案例四
String s1 = new String("a" + "b");
String s2 = "ab";
System.out.println(s1 == s2);//false
System.out.println(s1.intern() == s2);//true
System.out.println(s1 == s1.intern());//false

案例四分析

	1.常量池创建a,创建b,
	2.+则常量池创建ab,
	3.new String()则堆空间创建ab
  • 这样就很明显了,s1表示堆空间地址,s2表示常量池地址
  • s1.intern()先判断常量池有没有ab,发现有,ok,返回常量池中已存在的ab地址
  • 因此s1.intern()表示常量池地址
// 案例五
/**
 *注意:用append()拼接字符串和用 + new StringBuilder()拼接字符串,对结果并没有影响,无非是堆中有没有创建对象的区别
 */
String t1 = new StringBuilder("ab") + new StringBuilder("c").toString();
//String t1 = new StringBuilder("ab").append("c").toString();
System.out(t1 == t1.intern()); //true

String s1 = new StringBuilder("j") + new StringBuilder("ava").toString();
//String s1 = new StringBuilder("j").append("ava").toString();
System.out.println(s1 == s1.intern()); //false

案例五分析

	必须说下这个案例贼坑爹!!!
	先分析t1:
	1.new StringBuilder()在堆空间创建,t1表示堆空间的地址,存着abc,常量池不存在abc;
	2.所以t1.intern()会在常量池拷贝一份堆空间的地址过去,因此地址一样,true
	再分析s1:
	1.new StringBuilder()在堆空间创建,s1表示堆空间的地址,存着java字符串;
	2.但是这个时候常量池已经存在java字符串了!!!注意之所以存在,是因为"java"这个字符串特殊
	3.原因:当你运行这个方法时,会加载sun.misc.Version这个类,这个类会初始化java这个字符串,所以java这个字符串已经存在了,
	4.基于这个原因,返回false
	
多说一句,这个点之前真没有注意,确实也是在B站看视频面试题的过程中了解到的,
		 另外受到版本影响,有可能初始化的不是这个字符串。当然面试如果遇到了,默认就是java字符串

总结:

  1. ""表示常量池创建字符串对象,new的方式表示堆中创建字符串,
  2. " " + " "会在常量池创建字符串的连接

以上就是本人对String的==理解,如果有错,请指出来,以免误人子弟,谢谢

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值