前置知识
在Java7之前,JVM内存模型中有永久代(Premanent Generation的概念,方法区以此实现,字符串常量池就放在其中
在Java7之后字符串常量池等被移至堆区内,在Java8永久代被正式移除,取而代之的是元空间(MetaSpace)
例子
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
new String("1")执行后,生成了两个对象,一个是string对象,还有一个值为“1”的字符串常量
s.intern()因为常量存在,所以不会再次将"1"放入常量池
s2 = "1" 会直接获得字符串常量的引用,而s为字符串对象的实例引用,所以结果为false
new String("1") + new String("1");执行后同样也是两个对象和一个常量"1",最终合并为一个string对象,值为“11”,但是并没用放入字符串常量池
s3.intern()将“11"放入常量池,jdk6和jdk7的区别就在此
- jdk6中使用Intern()是若常量池中不存在此字符串,就将此字符串复制一份放入永久代的常量池中然后返回引用,引用存在于方法区,而s3的实例存在于堆区,所以对比地址肯定是不一样的
- jdk7的常量池在堆区,在
s3.intern()之后,常量池查无此字符串,不同于jdk6复制一份放入premGen中,而是先在堆区内寻找实例,将实例引用放入常量池,所以s4="11"获取的就是s3的实例引用