String中intern方法的作用

详见:https://blog.csdn.net/guoxiaolongonly/article/details/80425548

1.常量池存放于方法区中

2.jdk1.6 方法区放在永久代(java堆的一部分),jdk1.7 特别将字符串常量池移动到了的堆内存中(使用参数-XX:PermSize 和-XX:MaxPermSize指定大小),jdk1.8放在单独的元空间里面(-XX:MaxMetaspaceSzie设定大小),和堆相独立。所以导致string的intern方法因为以上变化在不同版本会有不同表现。

3.jdk1.6将Hotspot虚拟机使用永久代来实现方法区,因为方法区的内存回收跟堆内存回收其实没什么区别,这样实现可以用垃圾收集器来管理这部分内存,但这样容易导致内存溢出(达到-XX:MaxPermSize)。

JDK1.6,JDK1.7常量池的存放如下都存放于堆内存中

JDK1.8常量池的存放如下

具体可参考:https://blog.csdn.net/zhyhang/article/details/17246223/

知道了常量池在内存中的存放后,我们需要先了解一下 String str=“abc”;和 String str =new String(“abc”);的区别

1.String str=“abc”;

JDK1.6
(1) 当常量池中不存在"abc"这个字符串的引用,在堆内存中new一个String对象,复制这个对象加入常量池,返回常量池中的对象。

(2) 当常量池中存在"abc"这个字符串对象,str指向这个对象的引用;

JDK1.7以上
(1) 当常量池中不存在"abc"这个字符串的引用,在堆内存中new一个新的String对象,将这个对象的引用加入常量池。(跟1.6的区别是常量池不再存放对象,只存放引用。)
(2) 当常量池中存在"abc"这个字符串的引用,str指向这个引用;

2.String str =new String(“abc”)

单纯的在堆内存中new一个String对象,通过StringBuilder 跟StringBuffer 构建的对象也是一样

3.intern方法 (返回常量池中该字符串的引用)

(1) 当常量池中不存在"abc"这个字符串的引用,将这个对象的引用加入常量池,返回这个对象的引用。
(2) 当常量池中存在"abc"这个字符串的引用,返回这个对象的引用;

 详见:http://www.cnblogs.com/think-in-java/p/10418915.html

测试环境JDK1.8

常量池可以存放引用,也可以存放常量

String.intern()分析

 判断这个常量是否存在于常量池。
  如果存在
   判断存在内容是引用还是常量,
    如果是引用,
     返回引用地址指向堆空间对象,
    如果是常量,
     直接返回常量池常量
  如果不存在,
   将当前对象引用复制到常量池,并且返回的是当前对象的引用

   String a1 = "AA";
    System.out.println(a1 == a1.intern()); //true
    String a2 = new String("B") + new String("B");
    a2.intern();
    String a3 = new String("B") + new String("B");
    System.out.println(a2 == a3.intern());//true
    System.out.println(a3 == a3.intern());//false
    String a4 = new String("C") + new String("C");
    System.out.println(a4 == a4.intern()); //true

三.总结 

1.只在常量池上创建常量

   String a1 = "AA";

2.只在堆上创建对象

  String a2 = new String("A") + new String("A");

3.在堆上创建对象,在常量池上创建常量

  String a4 = new String("A") + new String("A");//只在堆上创建对象AA
    a4.intern();//将该对象AA的引用保存到常量池上

5.在堆上创建对象,在常量池上创建引用, 在常量池上创建常量(不可能)

 String a5 = new String("A") + new String("A");//只在堆上创建对象
    a5.intern();//在常量池上创建引用
    String a6 = "AA";//此时不会再在常量池上创建常量AA,而是将a5的引用返回给a6
    System.out.println(a5 == a6); //true

6.

四.练习

String aa = "AA";//设置常量AA到常量池
         String bb = "BB";//设置常量BB到常量池
         String ccdd = "CC"+"DD";//设置常量CCDD到常量池
         String neeff = new String("EE")+new String("FF");//设置EE和FF到常量池。并且添加EE、FF和EEFF对象到堆
         String aabb = aa+bb;//添加AABB对象到堆
         String gghh = "GG"+new String("HH");//设置GG和HH常量到常量池,设置HH和GGHH对象到堆
//         aa.intern();//啥事都不做,返回AA常量
//         ccdd.intern();//啥事都不做,返回CCDD常量
//         neeff.intern();//添加EEFF对象的引用到常量池,并返回EEFF对象
//         aabb.intern();//添加AABB对象的引用到常量池,并返回AABB对象
//         gghh.intern();//添加GGHH对象的引用到常量池,并返回GGHH对象
         System.out.println(aa.intern()==aa); //true
         System.out.println(neeff.intern()=="EEFF");//true
         System.out.println("EEFF"==neeff);//true
         String nccdd = new String("CCDD");
         System.out.println(ccdd==nccdd);//false
         System.out.println(ccdd==nccdd.intern());//true
         System.out.println(aabb.intern()==aabb);//true
         System.out.println(gghh==gghh.intern());//true
原文地址:https://www.cnblogs.com/lukelook/p/10894481.html