关于java字符串创建与常量池的关系,之前能分清的一些点现在有些记忆模糊了,做一个学习笔记。
String字符串的两种创建方式
1.new关键字创建
String s1 = new String("aa");
这种方式有可能会创建两个对象。
首先去字符串常量池中找有没有"aa",发现没有,就会在字符串常量池中创建"aa"。
然后在堆中创建一个新对象"aa",并且返回引用。s1指向的就是堆中的这个对象。
2.字面量创建
String s2 = "bb";
用字面量"bb"直接对s2初始化。
这种方式会先到字符串常量池中去找有没有"bb",如果有直接返回"bb"的引用;如果没有就在字符串常量池中创建这个对象,然后返回它的引用。
intern()方法
intern
public String intern()
Returns a canonical representation for the string object.
A pool of strings, initially empty, is maintained privately by theclass String.
When the intern method is invoked, if the pool already contains astring equal to this String object as determined bythe equals(Object) method, then the string from the pool isreturned. 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 t, s.intern() == t.intern() is trueif and only if s.equals(t) is true.
All literal strings and string-valued constant expressions areinterned. 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 isguaranteed to be from a pool of unique strings.
当调用intern()方法的时候,如果字符串常量池已经有这个字符串了,就直接返回字符串常量池中的字符串;否则把此对象添加到字符串常量池,并且返回它的引用。(注:1.7之后版本)
对两种方式创建的字符串对象都分别调用一下intern()方法:
String s1 = new String("aa");
String s2 = "bb";
String s3 = "aa";
System.out.println(s1.intern()==s1);//false
System.out.println(s2.intern()==s2);//true
System.out.println(s1.intern()==s3);//true
第一个输出fasle。s1指向堆,s1.intern()指向字符串常量池。
第二个输出true。s2指向字符串常量池,s2.intern()也指向字符串常量池。
第三个输出true。s3指向字符串常量池,s1.intern()指向字符串常量池。
通过上述例子可以稍稍明白字符串创建与字符串常量池的关系。那么再看一个特殊例子:
String s4 = new String("a") + new String("b");
System.out.println(s4.intern()==s4);//true
同样是用new关键字创建,怎么s4.intern()==s4
的结果与s1.intern()==s1
的结果不一样?来看s4的初始化过程。
首先去字符串常量池判断是否有"a"和"b",发现没有,于是在字符串常量池中创建"a"和"b"。
然后轮到new关键字,在堆中创建了"a"和"b"两个对象之后,会把它们相加之后的对象"ab"给到s4。
此时s4指向堆中的"ab",而字符串常量池中是没有"ab"这个对象的。
所以对s4调用intern()方法时,去字符串常量池中找不到"ab",就会把堆中的"ab"放到字符串常量池中去,再返回它的引用。那么s4.intern()==s4
当然就会返回true
了。
关于字符串常量池的存储位置到底在哪里,说法太多了,有一位博主做了详细的测试,我认为是可信的:java8以后字符串常量池的位置,以及元空间的探秘,使用VisualVM进行实战验证