在jdk7,常量池从方法区移到了堆中,并且intern方法发生了改变;
在jdk6,internintern方法还是会先去查询常量池中是否有已经存在,如果存在则返回常量,如果不存在,则复制一份到常量池;并返回该引用;
// JDK1.7及以后,intern方法还是会先去查询常量池中是否有已经存在,
//如果存在,则返回常量池中的引用,这一点与之前没有区别,区别在于,
//如果在常量池找不到对应的字符串,则不会再将字符串拷贝到常量池,而只是在常量池中生成一个对原字符串的引用。
//简单的说,就是往常量池放的东西变了:原来在常量池中找不到时,复制一个副本放到常量池,
//1.7后则是将在堆上的地址引用复制到常量池。
//证明 环境java8
@Test
public void testName5() throws Exception {
String str2 = new String("str")+new String("01");
//此时常量池存放的是str2的引用地址
str2.intern();
//获取的是str2的引用地址
String str1 = "str01";
System.out.println(str2==str1);//true
}
@Test
public void testName5_0() throws Exception {
String str2 = new String("str")+new String("01");
// str2.intern();
//此时常量池中是字符串str01
String str1 = "str01";
//此时intern获取的是常量池的字符串str01
System.out.println(str2.intern()==str1);//true
}
@Test
public void testName5_1() throws Exception {
//不会放入常量池
String str2 = new String("str")+new String("01");
//此时常量池中是字符串str01
String str1 = "str01";
//因为常量池已经存在字符串str01,此时操作没有意义了
str2.intern();
System.out.println(str2==str1);//false
}
//综合
@Test
public void testName3_2() throws Exception {
String s=new StringBuilder("aa").append("bb").toString();
String s1=new StringBuilder("哈哈").append("你好").toString();
String s2=new StringBuilder("jk").toString();
//此时常量池已经有了字符串12
String s3=new String("12");
String s4="33";
//s.intern()获取是s的引用
System.out.println(s.intern()==s);//true
System.out.println(s1.intern()==s1);//true
//这个个人认为JVM做了优化,变成了new String("jk");导致常量池有了jk,于是false
System.out.println(s2.intern()==s2);//false 这个是为什么???
//s3.intern()获取是常量池的字符串12,所以为false
System.out.println(s3.intern()==s3);//false
System.out.println(s4.intern()==s4);//true
}
//证明jdk7,常量池从方法区移到了堆中
//java.lang.OutOfMemoryError: Java heap space
//-Xmx5m -Xms5m -XX:-UseGCOverheadLimit
//设置堆内存的最大最小值
@Test
public void testName4() throws Exception {
List<String> list=new ArrayList<>();
int i=0;
while(true) {
list.add(("A"+i++).intern());
}
}
本文详细解析了JDK7中字符串常量池的重要变动,包括其从方法区移至堆区的影响,以及intern方法行为的变化。在JDK7及以后,intern方法在常量池中生成的不再是字符串副本,而是指向堆上字符串的引用,通过实例对比展示了这一变化带来的效果。
373

被折叠的 条评论
为什么被折叠?



