前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >java字符串中关于==的理解

java字符串中关于==的理解

作者头像
joshua317
发布2024-03-09 08:14:51
750
发布2024-03-09 08:14:51
举报
文章被收录于专栏:技术博文技术博文

先看一段代码

代码语言:javascript
复制
public class Test1{
    public static void main(String[] args) {
        System.out.println(isAdmin("Joshua317"));
    }

    public static boolean isAdmin(String userId)
    {
        System.out.println(userId.toLowerCase());
        return userId.toLowerCase() == "joshua317";
    }
}

结果返回了false

原因

对于两个引用变量,只有他们指向同一个引用时,==才会返回true。代码中"joshua317"指向堆内存字符串常量池里joshua317的地址,而String类的方法都是通过创建新的对象也就是new String()的方式返回的,因此userId.toLowerCase()指向的是这个字符串对象在堆内存中的地址。如果代码中isAdmin方法返回值更改为return userId.toLowerCase().equals("joshua317"),输出结果将变为true。

继续理解

Java中的==表示的是什么呢?有时候很令人费解。比如,以下例子输出是什么?

代码语言:javascript
复制
public class Test3 {
    public static void main(String[] args) {

        //demo1
        String str = "joshua317";
        String str1 = "joshua317";
        System.out.println("demo1:" + (str == str1));//true

        //demo2
        String str2 = new String("joshua317");
        String str3 = new String("joshua317");
        System.out.println("demo2:" + (str2 == str3));//false

        //demo3
        int i1 = 1;
        int i2 = 1;
        System.out.println("demo3:" + (i1 == i2));//true

        //demo4
        TestObject t1 = new TestObject();
        TestObject t2 = new TestObject();
        System.out.println("demo4:" + (t1 == t2));//false
    }
}

class TestObject {
    public TestObject(){

    }
}

其实,在Java中,如果是基本数据类型,则 == 比较的是值;如果是对象类型,则 == 比较的是对象的地址。但是,有时候会疑惑,String不是对象类型么?为什么demo1是true呢?这个就要谈谈字符串常量池的问题。

字符串常量池

String类是我们平常项目中使用频率非常高的一种对象类型,JVM为了提升性能和减少开销,避免字符串的重复创建,维护了一块特殊的内存空间,即字符串常量池。当需要使用字符串时,先去字符串常量池查看该字符串是否已经存在,如果存在,则可直接使用;如果不存在,初始化,并将该字符串放入到字符串常量池中。

在JDK1.6及之前版本,字符串常量池在方法区中

在JDK1.7及以后版本,字符串常量池移到了堆中

使用String str="joshua317",可能创建一个或者不创建对象。如果"joshua317"在字符串常量池中已经存在,则不会再创建String类型的值为"joshua317"的对象,而是将str指向这个"joshua317"对象内存地址,后续无论用这种方式创建多少个指向"joshua317"的引用,在内存中,都只有一个"joshua317"内存地址被分配。而==判断的是对象内存的地址,所以demo1返回true。下图是用这种方式创建字符串的示例图。

对象存放在堆中,字符串常量池是堆中一块特殊区域,new出来的是对象,字符串可以通过直接赋值创建一个对象,如上所述。

对象的引用存放在栈中,String str是对象的引用

在上图中,栈存放的是字符串的引用,str和str1存放的都是对象"joshua317"的内存地址,==判断对象时,判断的是他们存储的内存地址是否相同,由上图可见,他们的内存地址是相同的,所以demo1输出的是true。

demo2的两个字符串都是通过new的方式创建对象的,所以在堆上有两个String对象,且这两个对象指向字符串常量池中的同一个对象"joshua317",如上图所示,此时str2和str3存储的对象地址就不相同,所以demo2返回的是false。

String str = new String("joshua317")创建了几个对象?如果字符串常量池中没有"joshua317",则该句创建了两个对象,首先会创建一个"joshua317"存放在字符串常量池中,其本身就是一个对象;然后会new 一个字符串对象,并将"joshua317"的引用返回给new出来的对象;如果字符串常量池中有"joshua317",则该句只创建了一个对象,因为该句首先会查找字符串常量池中是否存在"joshua317",如果存在则直接返回"joshua317"的引用给new出来的对象。

总结

如果是基本数据类型,==判断的是值

如果是对象类型,==判断的是对象的地址

通过直接赋值而不是new的方式给String赋值,如果字符串常量池中有该对象,则不会再创建,此时通过 == 判断,返回的是true。如: String str="joshua317"; String str1="joshua317"; str == str1为true.

在JDK1.6及以前版本,字符串常量池在方法区中;

在JDK1.7及以后,字符串常量池在堆中。对象的引用保存在栈中

本文为joshua317原创文章,转载请注明:转载自joshua317博客 https://www.joshua317.com/article/310

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2024-03-08,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档