String#intern
java1.6内存分布

java1.8内存分布

官方声明因为经常会永久代内存不够用或者内存泄露。
JDK1.6 String
关于String创建问题,首先要先了解字符串常量池,String不是基本数据类型,所以分配也是比较耗费资源的,但是String又是final的,所以后来为了节省空间提高效率进行了优化:使用了字符串常量池。避免了创建相同的字符串.
String str1 = new String("1");
str1.intern();
String str2 = "1";
System.out.println(str1 == str2);
String str3 = new String("1") + new String("1");
str3.intern();
String s4 = "11";
System.out.println(str3 == s4);

前提:在JDK1.6中,真正存放字符串常量池的是永久代,但是永久代与堆空间是物理隔离的,所以在堆中的对象执行intern()就相当于在字符串常量池中新建一个对象。
String str1 = new String("1"); 在字符串常量池中创建了一个"1"[因为是字面量,所以就会自动加载进字符串常量池],并且在堆中也有一个“a”的对象,但是此时他两并没关系
str1.intern(); 去字符串常量池去找"1",若不存在,则相当复制一个"1"到字符串常量池中,但是此时已经存在"1"了,所以就会将“1”的引用返回,又因为没有接受,所以相当于什么也没做
String str2 = "1"; 字面量,所以会去字符串常量池中找“1”,因为有“1”,所以直接返回字符串常量池中的“1”的引用
String str3 = new String("1") + new String("1"); 这句总共会产生4个String[1,1,11,常量池中的[1]],1个StringBuilder对象。
str3.intern(); 去字符串常量池去找"1",此时不存在,就复制一个"11"对象到字符串常量池中
String s4 = "11"; 去字符串常量池中找,存在返回了字符串常量池中的引用
JDK1.7 String
String str1 = new String("1");
str1.intern();
String str2 = "1";
System.out.println(str1 == str2);
String str3 = new String("1") + new String("1");
str3.intern();
String s4 = "11";
System.out.println(str3 == s4);

这段代码与上面唯一的区别就是JDk1.7之后将字符串常量池移动到了堆中,因为同属一片内存,所以intern()不会复制一个对象,而是将该对象的引用保存下来,所以当String s4 = "11"; 当str4去创建的时候会发现已经存在了,然后会返回该字符串的引用,所以会与str3指向一个位置
String str1 = new String("1");
str1.intern();
String str2 = "1";
System.out.println(str1 == str2);
String str3 = new String("1") + new String("1");
String s4 = "11";
str3.intern();
System.out.println(str3 == s4);

这段代码唯一区别就是str3.intern()在String s4 = "11";之后执行,因为先执行了String s4 = "11",所以会在字符串常量池中保存一个“11”对象, 所以之后就算调了intern()方法返回的也不是同样的值
SUMMARY:直接使用双引号声明的String对象会直接存储到常量池中。如果直接使用new String(),那么只会在堆上创建对象,而不会去常量池中创建,只有在使用String#intern时才会去字符串常量池中创建,但是在JDK6与7版本中方式不同:JDK6会相当于在字符串常量池中复制一个对象,并且返回字符串常量池中的引用。JDK7版本将String常量池从永久代移动到了堆,String#intern方法,如果存在堆中的对象,会直接保存对象的引用,不会重新创建对象,然后返回该引用。

浙公网安备 33010602011771号