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. 第一行是两个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. 在执行到第二行的时候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

  • 案例
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

在这里插入图片描述

创建了几个对象

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

直接写双引号常量来创建

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

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

在这里插入图片描述

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是本身常量池的地址)
    • 如果是引用,返回引用地址指向的堆空间对象地址值
    • 如果是常量,则直接返回常量池常量的地址值
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);

在这里插入图片描述

两个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

在这里插入图片描述

双引号字符串常量与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

在这里插入图片描述

  • 分析

如果换成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()); 

在这里插入图片描述

  • 分析

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

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值