String s = new String(“1“) +new String(“1“) 和 intern()

字符串常量池到底保存的是字符串对象还是字符串对象的引用?

首先看一下intern()的注释

/** 
 * Returns a canonical representation for the string object. 
 * <p> 
 * A pool of strings, initially empty, is maintained privately by the 
 * class <code>String</code>. 
 * <p> 
 * When the intern method is invoked, if the pool already contains a 
 * string equal to this <code>String</code> object as determined by 
 * the {@link #equals(Object)} method, then the string from the pool is 
 * returned. Otherwise, this <code>String</code> object is added to the 
 * pool and a reference to this <code>String</code> object is returned. 
 * <p> 
 * It follows that for any two strings <code>s</code> and <code>t</code>, 
 * <code>s.intern()&nbsp;==&nbsp;t.intern()</code> is <code>true</code> 
 * if and only if <code>s.equals(t)</code> is <code>true</code>. 
 * <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&trade; 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. 
 */  
public native String intern();  

String 两种使用方式方式:
1、直接使用双引号声明出来的String对象会直接存储在常量池中。
2、如果不是用双引号声明的String对象,可以使用String提供的intern方法。当调用 intern 方法时,如果池已经包含一个等于此 String 对象的字符串(该对象由 equals(Object) 方法确定),则返回池中的字符串。否则,将此 String 对象添加到池中,并且返回此 String 对象的引用。

看下面两段代码:

第一段代码


public static void main(String[] args) {
    String s = new String("1");
    s.intern();
    String s2 = "1";
    System.out.println(s == s2);

    String s3 = new String("1") + new String("1");
    s3.intern();
    String s4 = "11";
    System.out.println(s3 == s4);
}

打印结果是

jdk6 下false false
jdk7 下false true

  	jdk6
  	s的引用指向的是在堆中对象,因为 jdk6中的常量池是放在 Perm 区中的,Perm 区和正常的 JAVA Heap 区域是
  完全分开的。因为code1 已经new String("1" )此时在堆中产生了一个对象,在Perm区的字符串常量池中也产生了"1"
  对象,s4显示声明的时候发现字符串常量池中已经存在了就直接引用(此时指向了Perm区),而s是指向堆中的对象,即便s.intern()之后,
  s引用堆中,s2引用指向Perm区,==又判断的是引用地址,所以肯定输出false
  
  s3 和 s4同理, new String("1") + new String("1"); 会在堆中产生一个"11"对象(堆中两个对象相加还是放在堆中),在字符串常量池中
  产生"1",
  s3调用intern()后把"11"放到字符串常量池中,但是此时s3指向的是堆中,s4还是指向的Perm区,比较引用地址还是输出false

	jdk7
	jdk7以后将在 Jdk6 以及以前的版本中,字符串的常量池是放在堆的 Perm 区的,Perm 区是一个类静态的区域,主要存储一些加
	载类的信息,常量池,方法片段等内容,默认大小只有4m,一旦常量池中大量使用 intern 是会直接产生
	java.lang.OutOfMemoryError: PermGen space错误的。 所以在 jdk7 的版本中,字符串常量池已经从 Perm 区移到正常的 
	Java Heap 区域了。
	s 和 s2 是一样的,s指向堆中的对象,s2直接引用常量池的"1",引用地址比较还是输出false
	重点说一下s3和s4:
	为什么输出了true,是因为String s3 = new String("1") + new String("1"); 这时候产生了两个对象,一个
	是s3指向的对象在堆上(该对象为"11"),此时在常量池中还生成了"1"对象,所以为两个对象。
	在s3调用intern()后,会把s3引用的对象"11"地址返回给字符串常量池中(jdk7以后常量池既可以存放对象也可存放引用地址),
	这时候s4 = "11"时候检测到有"11",就将存放在常量池中s3的的地址返回给s4,所以 s3 == s4 输出true

引用文章部分推荐参考:https://tech.meituan.com/2014/03/06/in-depth-understanding-string-intern.html

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值