JDK1.8 String类 intern方法详解

官方文档

public String intern()

Returns a canonical representation for the string object.

A pool of strings, initially empty, is maintained privately by the class String.

When the intern method is invoked, if the pool already contains a string equal to this String object as determined by the equals(Object) method, then the string from the pool is returned. Otherwise, this String object is added to the pool and a reference to this String object is returned.

It follows that for any two strings s and ts.intern() == t.intern() is true if and only if s.equals(t) is true.

All literal strings and string-valued constant expressions are interned. String literals are defined in section 3.10.5 of the The Java™ Language Specification.

Returns:
a string that has the same contents as this string, but is guaranteed to be from a pool of unique strings.

翻译:当调用字符串str 的intern方法时,如果常量池中已经包含了一个字符串equalsstr,则直接从池中返回这个字符串的引用,否则,把字符串str添加到池中并且返回其引用。

   当且仅当s.equals(t)返回true时, ts.intern() == t.intern()才返回true。(注意jdk7及以上常量池中才开始存的地址引用,之前的都是直接把对象copy一份存到常量池,这点《深入理解java虚拟机》中有特别说明

 

《深入理解Java虚拟机》一书中,周志明老师举例用的时用的如下例子:

public class RuntimeConstantPoolOOM {
	public static void main(String[] args) {
		String str1 = new StringBuilder("计算机").append("软件").toString();
		System.out.println(str1.intern()==str1);//输出true
		
		String str2 = new StringBuilder("ja").append("va").toString();
		System.out.println(str2.intern() == str2);//输出false
	}
}

以上程序输出:true  false

原因解释:
用new命令时,虚拟机都会在堆中开辟一块新的内存,当程序执行完new StringBuilder("计算机").append("软件").toString()后,产生拼接后的“计算机软件”字符串在常量池是不存在的,所以把其堆地址存入常量池中,此时str1.intern()返回的是堆中刚创建的“计算机软件“的地址,
str1.intern()==str1返回true。

第二个字符串”java”,这个是一个特殊字符串,无论我们是否创建它,虚拟机的常量池中都包含的有该字符串。由于常量池已经包含”java“,所以str2.intern()返回的是常量池本身就存在的"java"字符串地址的引用。而str2是我们new出来的,它指向的时我们在堆中新开辟的一个地址,故
str2.intern() == str2返回false。

  

还有个问题时起初不理解为啥非要用StringBuilder类后面加append的方式做实验,把append后面去掉后发现输出的结果又变了,第一个输出也变成false了。

String str1 = new StringBuilder("计算机").toString();
System.out.println(str1.intern()==str1);//输出false

两次输出为啥不一样呢?就是去掉了append,因为当我们new StringBuilder("计算机")时,已经包含了“计算机”字符串,它会放入常量池中去,其地址不是我们主动new StringBuilder的这个地址,所以返回false。
关于这点网上有个流行的面试题目:String s = new String("xxx")创建了几个对象? 答案是两个。一个时"xxx",另一个时new 出来的,前面说道只要时new 都会重新在堆内存分配地址。

 

 

 

 

posted @ 2019-11-30 22:05  爱我别走111  阅读(664)  评论(0)    收藏  举报