预备知识:
- 对于jdk1.7以下的版本,常量池在方法区;对于jdk1.7及以上版本,常量池被放入到了堆空间中。
- 对象在堆区,对象引用在栈区,对象引用存储的是对象所在地址(对象访问有句柄方式和直接指针方式两种)。
- "=="用于判定两端的值是否相等。偷偷对值做一个定义:对于引用s来说,s的值表示s的内容所存放的地址。
以下参考SEU_Calvin的文章
String s = new String("1");//生成常量池中的“1” 和堆空间中的字符串对象,但引用s是指向堆区的对象的
s.intern();//s对象去常量池中寻找后发现"1"已经存在于常量池中了
String s2 = "1";//引用s2直接指向常量池中的“1”对象
System.out.println(s.intern() == s2);//true。二者都指向常量池中的对象
System.out.println(s == s2);//false。s指向堆区,s2指向常量池(对不同的jdk版本来说这都是两个位置)
//注意:下面这句只在常量池中生成了"1",并没有在常量池中生成"11"
String s3 = new String("1") + new String("1");
//对于jdk1.7以下,s3.intern()的做法是直接在常量池中生成一个 "11" 对象;
//对于jdk1.7及以上,s3.intern()直接在常量池中存储指向堆区的s3(这是个对象引用),
// 注意在此之前常量池中没有“11”,如果有的话s3.intern()就会直接指向"11"在常量池中的位置,这一点不同jdk是一样的。
System.out.println(s3==s3.intern());//true
//去常量池中创建对象,但是已经被s3.intern()创建过了,
// 所以其值等于s3.intern()创建的值,即s3的值
String s4 = "11";
//如果没有上面的s3.intern()语句的话下面的结果就会是false,
//即与s3.intern()相比,String s4 = "11"这句代码不会考虑堆区已存在的s3对象
System.out.println(s3 == s4);//true
以下参考Eric新之助的文章
StringBuilder的情形和String不太一样,StringBuilder并不对常量池进行操作。
String str1=new StringBuilder("计算机").append("软件").toString();
//对jdk1.7及以上,下一条语句为true,即str1.intern()直接在常量池中存储了str1。
//如果按照String的情况,如果上面一条语句在常量池分配了"计算机软件",
//那么str1.intern()应指向常量池中的位置,下一条语句应该为false。
System.out.println(str1.intern()==str1);
String str2=new StringBuilder("ja").append("va").toString();
//为false,"java"这个字符串在执行StringBuilder.toString()之前已经出现过,
//字符串常量池中早已有它的引用。涉及JVM的初始化操作。
System.out.println(str2.intern()==str2);