• String常量池理解



    更多博客内容访问只爱吃火龙果,点击了解详情


    String.intern()方法

    首先判断这个常量是否存在于常量池

    1. 如果存在,则直接返回地址值(只不过地址值分为两种情况,1是堆中的引用,2是本身常量池的地址)
    • 如果是引用,返回引用地址指向的堆空间对象地址值
    • 如果是常量,则直接返回常量池常量的地址值,
    1. 如果不存在,将当前对象引用复制到常量池,并且返回的是当前对象的引用
    • 案例
    public static void main(String[] args){
            String s1 = new String("1")+new String("23");
            s1.intern();
            String s2 = "123";
            System.out.println( s1 == s2);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    在这里插入图片描述

    • 分析:
    1. 第一行是两个new String类型的字符串相加,创建了堆中有3个对象 一个是1, 一个是23,还有一个是结果 123(在堆中),由于程序刚启动常量池也没有 1,23 所以会在常量池创建2个对象 (1 , 23)
    2. s1执行intern()方法之后,首先去常量池判断有没有123,此时发现没有,所以会把对象加入到常量池(堆中的地址),并且返回当前对象的引用(堆中的地址)
    3. 当创建s2时候,并且找到常量池中123,并且把常量池的地址值返回给s2(常量池的地址其实就是堆中的地址)
    4. 由于常量池的地址值就是s1调用intern()方法之后得到的堆中的引用,所以此时s1s2的地址值一样,输出true
    • 案例
    public static void main(String[] args){
            String s1 = new String("1")+new String("23");
            String s2 = "123";
            s1.intern();
            System.out.println( s1 == s2);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    在这里插入图片描述

    分析

    1. 在执行到第二行的时候String s2 = "123"时,发现常量池没有123,所以会在常量池中先创建一个常量(此时的常量地址不是堆中的地址,就是是在的常量池地址)
    2. 在当s1调用intern()方法时,会发现常量池已经有了123对象,就会直接把123的常量(地址)给返回出去,但是由于返回值并没有接收,所以此时s1还是堆中地址,则输出false
    3. 如果代码换成 s1 = s1.intern();那s1就会重新指向常量池了,那输出就为true
    • 练习
    String s = new String("1");  
    String s2 = "1";  
    s.intern();  
    //false
    System.out.println(s == s2);  
      
    String s3 = new String("1") + new String("1");  
    String s4 = "11";  
    s3.intern(); 
    //false
    System.out.println(s3 == s4);  
    
    String s = new String("1");  
    String s2 = "1";  
    s=s.intern();  
    //true
    System.out.println(s == s2); 
    
    String str1 = new String("SEU") + new String("Calvin");        
    System.out.println(str1.intern() == str1);  //true   
    // str1.intern()发现常量池中不存在“SEUCalvin”,
    //因此在常量池中创建"SEUCalvin",也就直接指向了堆中的str1了。
    System.out.println(str1 == "SEUCalvin"); //true
    
    
    String str2 = "SEUCalvin";//新加的一行代码,其余不变  
    String str1 = new String("SEU")+ new String("Calvin");      
    System.out.println(str1.intern() == str1);   //false
    System.out.println(str1 == "SEUCalvin");   //false
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 案例
    String s1 = "23";
    /*
    * 这里执行时,常量“1” 会首先到字符串常量池里面去找,如果没有就创建一个,
    * 并且加入字符串常量池。
    * 得到的123结果对象,不会存入到常量池。这里特别注意和两个常量字符串相加不同 “1”+“23” 
    * 由于不会进入常量池,所以s2 和 s3 常量池地址值不同,所以输出为false
    */
    String s2 = "1" + s1;
    String s3 = s2.intern();
    String s4 = "123";
    System.out.println(s3 == s4); //true
    System.out.println(s3 == s2); //true
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    在这里插入图片描述

    创建了几个对象

    String s1 = new String("123") 创建了几个对象,String s2 = "123" 创建 了几个对象

    直接写双引号常量来创建

    判断这个常量是否存在于常量池,

    • 如果存在,则直接返回地址值(只不过地址值分为两种情况,1是堆中的引用,2是本身常量池的地址)
      • 如果是引用,返回引用地址指向的堆空间对象地址值
      • 如果是常量,则直接返回常量池常量的地址值,
    • 如果不存在,在常量池中创建该常量,并返回此常量的地址值
    • 案例
     String  s = "123";
    //true,因为s已经在常量池里面了,s.intern()返回的也是常量池的地址,两者地址一样为true
    System.out.println(s == s.intern());
    
    • 1
    • 2
    • 3

    在这里插入图片描述

    new String创建字符串

    首先在堆上创建对象(无论堆上是否存在相同字面量的对象),然后判断常量池上是否存在字符串的字面量(字符串的值)

    • 如果不存在则在常量池上创建常量(并将常量地址值返回)
    • 如果存在不做任何操作
    • 案例
    String  s = new String("123");
    /*
    严格来说首先肯定会在堆中创建一个123的对象,然后再去判断常量池中是否存在123的对象,
    如果不存在,则在常量池中创建一个123的常量(与堆中的123不是一个对象),
    如果存在,则不做任何操作。
    因为常量池中是有123的对象的,s指向的是堆内存中的地址值,
    s.intern()返回是常量池中的123的常量池地址,所以输出false
    */
    String s2 = s.intern();
    System.out.println(s == s.intern());
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    在这里插入图片描述

    两个双引号的字符串相加

    判断这两个常量、相加后的常量在常量池上是否存在

    • 如果不存在则在常量池上创建相应的常量(并将常量地址值返回)
    • 如果存在,则直接返回地址值(只不过地址值分为两种情况,1是堆中的引用,2是本身常量池的地址)
      • 如果是引用,返回引用地址指向的堆空间对象地址值
      • 如果是常量,则直接返回常量池常量的地址值
    String s = "Hello,World";
    String str = "Hello" + "," + "World";
    String s1 = new String("123").intern();
    String s2 = "1" + "23";
    /*
    *  String  s1 = new String("123") 创建了两个对象(一个堆中,一个常量池中)
       此时s1指向堆中
    *  当s1调用.intern()方法之后,发现常量池中已经有了字面量是123的常量,
       则在常量池中创建一个对象,地址是堆内存地址,并返回给s1
    *  在执行s2等于123时候,去常量池查看,同上常量池已经存在了,
       则此时s2不创建对象,直接拿常量池123的地址值使用
    *  所以此时s1 和 s2 都代表是常量池的地址值,则输出为true
    */
    System.out.println(s1 == s2);
    System.out.println(s == str);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    在这里插入图片描述

    两个new String()的字符串相加

    首先会创建这两个对象(堆中)以及相加后的对象(堆中)然后判断常量池中是否存在这两个对象的字面量常量

    • 如果存在,不做任何操作
    • 如果不存在,则在常量池上创建对应常量
    String s1 = new String("1")+new String("23");
    /*
    *  首先堆中会有 1 ,23 ,以及相加之后的123 这三个对象。   
        如果 1,23 这两个对象在常量池中没有相等的字面量
    *  那么还会在常量池中创建2个对象 最大创建了5个对象。最小创建了3个对象都在堆中。
    */
    s1.intern();
    String s2 = "123";
    System.out.println( s1 == s2);// true
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    在这里插入图片描述

    双引号字符串常量与new String字符串相加

    首先创建两个对象,一个是new String的对象(堆中),一个是相加后的对象(堆中),然后判断双引号字符串字面量和new String的字面量在常量池是否存在

    • 如果存在,不做操作
    • 如果不存在,则在常量池上创建对象的常量
    • 案例
    String s1 = "1"+new String("23");
    /*
    *首先堆中会有 23 ,以及相加之后的123 这2个对象
    如果23,1 这两个对象在常量池中没有相等的字面量,那么还会在常量池中创建2个对象最多创建了4个对象(2个堆中,2个在常量池中)。最少创建了2个对象都堆中。
    */
    String s2 = "123";
    System.out.println( s1 == s2);// false
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    在这里插入图片描述

    • 分析

    如果换成System.out.println( s1.intern() == s2);则返回的是true
    在这里插入图片描述

    双引号字符串常量与一个字符串变量相加

    首先创建一个对象,是相加后的结果对象(存放堆中,不会找常量池),然后判断双引号字符串字面量在常量池是否存在

    • 如果存在,不做操作
    • 如果不存在,则在常量池上创建对象的常量
    String s1 = "23";
    /*
    * 这里执行时,常量“1” 会首先到字符串常量池里面去找,如果没有就创建一个,并且加入字符串常量池。
    * 得到的123结果对象,不会存入到常量池。这里特别注意和两个常量字符串相加不同于 “1”+“23” 
    * 由于不会进入常量池,所以s2 和 s3 常量池地址值不同,所以输出为false
    */
    String s2 = "1"+s1;
    String s3 = "123";
    System.out.println( s2 == s3.intern()); 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    在这里插入图片描述

    • 分析

    如果打印System.``_out_``.println( s2.intern() == s3.intern())``; 则返回结果为true,因为s2.intern()回去常量池中找有没有123常量,发现有则直接返回常量地址,而123又是常量池地址(非堆引用地址)

  • 相关阅读:
    面试中常问的SQL注入题
    Easyui里的datagrid嵌入select下拉框
    Java检测是否包含首字符串startsWith() 方法
    BUUCTF学习(四): 文件包含tips
    STM32F103C8T6 + 0.96“ I2C OLED显示3D_Cube
    用UNIGUI实现的网络共享打印(云打印)效果
    物联网助力智慧农业,农民也能成为科技工作者
    redis集群
    《ClickHouse原理解析与应用实践》读书笔记(2)
    API 管理调研
  • 原文地址:https://blog.csdn.net/u010859650/article/details/126870913