zoukankan      html  css  js  c++  java
  • jdk1.8下字符串常量的判断,String.intern()分析

    字符串常量池在jdk升级过程中发生了一些变化

          在JDK1.6中,它在方法区中,属于“永久代”.

                         在JDK1.7中,它被移除方法区,放在java堆中。

                         在JDK1.8中,取消了“永久代”,将常量池放在元空间,与堆独立

    jdk1.6中,intern()方法会把首次遇到的字符串示例复制到永久代中,返回的也是永久代中这个字符串实例的引用

    jdk1.6以后,对于实例,intern()方法不会再复制实例,只是在常量池中记录首次出现的实例引用,对于字符串仍然是加入字符串常量

    比如下面这段代码,这段代码在常量池加入的直接是“ab”的引用

    String s = new String("a")+new String("b")
    s.intern()

     

    创建字符串分析

    以下转自 https://blog.csdn.net/u013366617/article/details/83618361

    1.直接使用双引号创建字符串

     判断这个常量是否存在于常量池,
      如果存在,
       判断这个常量是存在的引用还是常量,
        如果是引用,返回引用地址指向的堆空间对象,
        如果是常量,则直接返回常量池常量,
      如果不存在,
        在常量池中创建该常量,并返回此常量

    String a1 = "AA";//在常量池上创建常量AA
    String a2 = "AA";//直接返回已经存在的常量AA
    System.out.println(a1 == a2); //true
    
    String a3 = new String("AA"); //在堆上创建对象AA
    a3.intern(); //在常量池上创建对象AA的引用
    String a4 = "AA"; //常量池上存在引用AA,直接返回该引用指向的堆空间对象,即a3
    System.out.println(a3 == a4); //false 这里一开始写错了
    注意!!!对上面的做个小小的解释
    String a3 = new String("AA"); //在堆上创建对象AA a3.intern(); String a4 = "AA"; System.out.println(a3 == a4); //false 对比 String a3 = new String("AA").intern(); //在堆上创建对象AA String a4 = "AA"; System.out.println(a3 == a4); //true 是不是感觉很奇怪 原因是a3.intern()确实返回的是常量池里的引用,但是不是a3本身,a3本身还是实例对象的引用 如果这样写 String a3 = new String("AA"); //在堆上创建对象AA String a = a3.intern(); String a4 = "AA"; System.out.println(a == a4); //true

    2.new String创建字符串

     首先在堆上创建对象(无论堆上是否存在相同字面量的对象),
     然后判断常量池上是否存在字符串的字面量,
      如果不存在
       在常量池上创建常量
      如果存在
       不做任何操作

    String a1 = new String("AA");
    String a2 = new String("AA");
    System.out.println(a1 == a2); //false
    
    //如果常量池上不存在常量AA,也不存在引用AA,则创建常量AA
    String a1 = new String("AA");
    System.out.println(a1 == a1.intern()); //false


    3.双引号相加

     判断这两个常量、相加后的常量在常量池上是否存在
      如果不存在
       则在常量池上创建相应的常量
      如果存在
       判断这个常量是存在的引用还是常量,
        如果是引用,返回引用地址指向的堆空间对象,
        如果是常量,则直接返回常量池常量,

    String a1 = "AA" + "BB";//在常量池上创建常量AA、BB和AABB,并返回AABB
    
    //常量池上存在常量AABB
    String a2 = "AABB";
    String a3 = "AA" + "BB";
    System.out.println(a2 == a3); //true
    
    //常量池上存在引用AABB
    String a4 = new String("AA") + new String("BB"); //在堆上创建对象AA、BB和AABB,在常量池上创建常量AA和BB
    a4.intern();
    String a5 = "AA" + "BB";
    System.out.println(a4 == a5); //true

    4.两个new String相加

     首先会创建这两个对象以及相加后的对象
     然后判断常量池中是否存在这两个对象的字面量常量
      如果存在
       不做任何操作
      如果不存在
       则在常量池上创建对应常量

    //常量AA不存在,所以第一步在常量池中创建了常量AA
    String a2 = new String("AA") + new String("BB");
    String a3 = new String("A")+new String("A"); //创建对象AA
    System.out.println(a3 == a3.intern()); //false
    
    //只在堆上创建AABB对象,没有在常量池中创建常量AABB
    String a2 = new String("AA") + new String("BB");
    System.out.println(a2 == a2.intern()); //true


    5.双引号字符串与new String字符串

     首先创建两个对象,一个是new String的对象,一个是相加后的对象
     然后判断双引号常量与new String的字面量在常量池是否存在
      如果存在
       不做操作
      如果不存在
       则在常量池上创建对象的常量

    String a1 = "AABB";
    String a2 = "AA" + new String("BB");
    System.out.println(a1 == a2.intern());//true
    System.out.println(a2 == a2.intern()); //false

    二.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 a3 = new String("AA");


    4.在堆上创建对象,在常量池上创建引用

    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

    练习

    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
  • 相关阅读:
    一个测试HTML Method的例子
    eXtplorer:在线管理网站文件的利器
    PHPXref:PHP文件交叉引用工具
    统计MySQL数据库大小
    PHP函数glob()
    PclZip:PHP压缩与解压缩
    PHP发送有附件的电子邮件[转]
    查找表中的主键
    CentOS6.4简单配置Cobar
    CentOS6.4 安装mysql cmake的参数说明
  • 原文地址:https://www.cnblogs.com/pokid/p/10437716.html
Copyright © 2011-2022 走看看