开始之前先了解下常量池:https://blog.csdn.net/xdugucc/article/details/78193805
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.
*/
public native String intern();
这里大概意思是intern用来返回常量池中的某字符串的引用,如果常量池中已经存在该字符串,则直接返回常量池中该对象的引用。否则,在常量池中加入该对象,然后 返回引用。值得注意的是下面的一段话,
* All literal strings and string-valued constant expressions are
* interned.
也就是说只对字符串值还有静态的字符串的值表达式有值相同返回的引用就一定是相同的
直接来看一些测试例子来加深下理解
public class Main {
public static String CONSTSTRING = "ef";
public static void main(String[] args) {
String a ;
String b;
String c;
a = new String("a");//这里看起来创建了两个对象,常量池中"a",还有heap中String a;不过下面的b="a"在编译期就在POOL创建了"a",所以只是创建了一个
b = "a";
pl(a==b);//false引用不同
pl(a.intern()==b);//true;这里a.intern()找到并给回了POOL中"a"的引用,所以true
a = new String("1")+new String("1");
b = "11";
pl(a.intern()==b);//true; 据说jdk1.7之前false, jdk1.7之后true,笔者1.8;这里可以看出是根据value来执行的
a.intern();//值得注意intern不会改变对象的引用
pl(a==b);//因此这里是false
/*
值得注意intern中的
* All literal strings and string-valued constant expressions are
* interned.
也就是说只对字符串值还有静态的字符串的值表达式,不能有引用
*/
a="a"+"b";
b="ab";
pl(a==b);//true
String temp = new String("aa");
a="a"+temp;
b="aaa";
pl(a.equals(b));//true;
pl(a.intern()==b);//false,因为temp是对象的引用,即使是满足a.equal(b)==true
c="bc";
a="a"+c;
b="abc";
pl(a == b);//false 同样的这样也不行
a="ef";
pl(a==CONSTSTRING);//字符串常量满足
a="cd"+CONSTSTRING;
b="cdef";
pl(a==b);//false;CONSTSTRING也是引用
}
public final static void pl(Object object){
System.out.println(object);
}
}
参考自https://www.cnblogs.com/Kidezyq/p/8040338.html
其中有些地方笔者认为有误,但是要详细的多,可能是程度不够吧
jdk1.7以上,因为常量池放到了堆里,因此大部分虚拟机的intern的实现知识在常量池中记录首次出现的实例的引用
String a = new String("a");
pl(a.intern() ==a);//false
a = new StringBuilder("b").append("c").toString();
pl(a.intern() == a);//true