【Java SE】字符串常量池详解,什么情况下字符串String对象存在常量池,通过==进行判断,字符串创建及截取后是否同一个对象

复习字符串创建方式

字符串的3+1种构造方法

  1. public String();创建一个空白字符串, 不含有任何内容
  2. public String(char[] array);根据字符数组的内容,来创建对应的字符串
  3. public String(byte[] array);根据字节数组的内筒,来创建对应的字符串
String str1 = "abc";
String str2 = "abc";
new String();
char[] charArray = new char[]{'a', 'b', 99};
String str3 = new String(charArray);

byte[] by1 = new byte[2];
by1[0] = 23;
by1[1] = 12;
String str4 = new String(by1);

对应内存情况见下图

1 种直接创建 String str = "Hello";注意:直接写上双引号,就是字符串对象。只要是字符串一定是对象
只有1种直接创建的字符串在堆中的字符串常量池中,其他3种new 创建的都在堆其中char数组是先转化为byte数组,然后构造成字符串的,这些char数组,byte数组都在堆中。

拼接,截取操作后得到的字符串是否在常量池。(判断标准)

直接
在这里插入图片描述

  • 常量池的字符串内容相同就是一个对象,用==比较是不是一个字符串对象
  • 用concat(String)拼接字符串;用+拼接字符串;
  • 从其他字符串中截取substring(2种);
  • 用replace替换字符串中字符得到返回值。
  • 用split分割得到字符串数组。
  • 假设得到的字符内容都是abcabc,检查最终得到的字符串是否在常量池中
public class MainTest {
    public static void main(String[] args) {
        //以下所有比较的字符串内容相同
        String str = "abcabc";
        String strCopy = "abcabc";
        String str1 = "ab".concat("cabc");
        String str2 = "a" + "bca" + "bc";
        String str22 = "bca";
        String str3 = "a" + str22 +"bc";
        String str4 = "aecaec".replace("e","b");
        String[] strArr1 = "abcabceartdeagfdseae".split("ea");
        String str5= strArr1[0];

        System.out.println(str == str1);//false//方法拼接的str1在堆
        System.out.println(str == str2);//true//字符串常量+拼接的字符串str2,在常量池
        System.out.println(str == "a" + "bca" + "bc");//true//字符串常量+拼接的匿名字符串结果,也在常量池
        System.out.println(str == str3);//false//其中有str22字符串引用参与拼接,str3在堆
        System.out.println(str == str4);//false//方法替换得到的str4在堆
        System.out.println(str == str5);//false//方法截取得到的str5在堆
        System.out.println(str == strCopy);//true//直接创建的在常量池

       
		String str11 = "aaa";
        String str88 = "aaa";
        System.out.println("str8:" + str11 == "str8:aaa");//false//+优先级高,最终笔试双方为 "str8:aaa" == "str8:aaa"虽然内容相同,equals必true。但"str8:" + str11得到的字符串在堆,后者在常量池,并不是同一个对象,也不是同一个地址。因为str11是字符串引用,“+”拼接在运行期间
        System.out.println(("str8:" + str11) == "str8:aaa");//false//同上
        System.out.println(("str8:" + str11).equals("str8:aaa"));//true,内容相同。
        
        System.out.println("str8:" + (str11 == "aaa"));//str8:true//str11也是直接创建的,就在常量池

    }
}

重点对比str2、str3
都是用+拼接,怎么一个在常量池,一个不在?
注意区分字符串常量字符串引用,即一个直接创建且匿名一个有名字

  • str2在常量池因为:
    字符串常量拼接在编译期间就已经完成,“+”号操作时处于编译时期。编译完后的“abcabc”放入常量池
  • str3在堆因为:
    字符串引用的拼接在运行时执行,“+”号操作时处于运行时期。执行完语句后创建一个新的字符串引用str3在堆来接收"a" + str22 +"bc"的结果。其中“a” ,str22和“bc”都在常量池,因为都是直接创建的,只有str3这个用引用有str22参与,“+”号拼接的在堆。

总结:

  • 对于String,属于引用类型,而==比较引用类型,必须得是同一个对象才true。
    在常量池的字符串只要内容一样,就是同一个对象
  • 而使用空参,字符数组,字节数组这3种方式创建的String对象(还有使用字符串常用方法拼接、截取、替换得到的String)(和+拼接字符串引用得到的String对象), 以上字符串, 内容相同也不是同一个对象,因为不在常量池中保存。 在堆中保存
  • 直接创建的字符串,和+ 拼接字符串常量得到的String对象,都保存在堆中的字符串常量池中保存。特点:只要内容相同,就是同一个对象。即内容相同用==比较为true
  • 对于sout("str8:" + str1 == "str8:aaa")因为 + 优先于 == 实际比较的是 “str8:” + str1(即str8:aaa)和 后续的字符串比较,明明内容相同为啥false呢,因为“字符串引用”经过+拼接得到的字符串也不在常量池。不是一个对象
    用equals比较就相同了,因为equals比较File,Data,String和包装类是比较的内容,而不是地址,所以不要求必须是同一个对象才true。因为这几个类重写了equals方法
  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值