Java中关于字符串值的比较(常量池)

首先,先解释一下几个关键字:

1、常量池

常量池可以理解为在堆内存中开辟的一块空间,它只适用于 String 类,“常量池”的出现是为了方便取用某些需要重复引用的东西,在使用前可以先在常量池中查找,如果没有则创建一个,同时也避免了资源浪费

2、字面量

可以理解为变量的值,例如:

    int a = 10;   //10 即为字面量
    String str = "abc";   //abc 为字面量

下面我们说一下比较字符串值的几种情况

1、直接赋值

  • 以 “” 方式创建的字符串,只要字符序列相同(顺序和大小写),无论在程序代码中出现几次,JVM 都只会建立一个 String 对象存储在常量池中(请参考下面的 字符串共享),并在字符串池中维护
    String str = "abc";
    String str1 = "abc";
    System.out.println(str == str1); //结果为 true
  • 创建对象 str
    我们在创建 str 的时候,因为在此之前没有声明过该对象,那么在常量池中也就不会有对应的字面量 abc,这个时候就会在常量池中开辟一块空间存储这个字面量 abc
  • 创建对象 sr1
    因为我们之前已经创建了 str ,而 str 的值和 str1 的字面量 abc 又是一样的,所以在创建 str1 对象的时候它就也指向了常量池中的字面量 abc ,这是就触发了一个新的概念(字符串共享
字符串共享:
  • 当创建一个对象时,如果该对象的字面量和常量池中存在字面量一致,那么它就不再创建一个新的字面量,而是也指向之前的字面量,也就意味着两个字符串对象所指向的地址值是相同的,所以 str == str1 ,该种情况可以避免重复对象的产生
第二种直接赋值的情况:
        String str = "1" + "2" + "3";
        String str1 = "1" + "23";
        String str2 = "123";
  • 针对以上三种赋值的方法,事实上它们的值在代码底层都会解析为 “123”,该种形式叫做编译优化,我们在执行 .java 文件的时候,通过会生成一个编译后的文件,也就是以 .class 后缀结尾的文件,以上面的例子来讲,该代码在class文件编译后的结果如下

  • 所以可以看出,代码中的三句输出的结果一定都为 true

在这里插入图片描述

2、通过构造函数创建字符串对象

  • 每次使用new创建对象时,都会在堆内存中申请新空间来存储字符串对象,所以,通过构造方法创建的每一个字符串对象都是单独存储在堆内存中的,不存在字符串的共享

例如:

String str1 = "abc";                //直接赋值
String str2 = new String("abc");    //通过构造函数创建
System.out.println(str1 == str2);   //结果为 False
  • 当该语句执行之后,main 方法会进行压栈,此时,创建的对象会在堆内的常量池中查询是否已经存在abc,如果不存在,则在字符串常量池中创建该字符串,并且在堆内开辟一个空间,将堆内存中的地址值赋值给 str1.如果常量池中已经存在该字符串,则直接在堆内存内开辟空间并将地址值赋给 str1

  • 等于说创建了两个对象,一个字符串对象,存储在堆内存中,另一个为 abc,存储在常量池中

  • 此时将 str1str2 的值进行比较,他对比的是两个对象的内存地址,str1 指向的是常量池中的 abc,而 str2 指向的是堆内存中的 new string,内存地址不同,所以结果为 False

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值