一篇文章搞懂最容易入的坑之一:java语言中equals和==的区别,同时也搞清栈和堆,基本数据类型和引用数据类型等基本概念的区别

经常我们在比较字符串是否相等时,会使用==或equals方法。但往往却得不到自己想要的结果。纠其原因,是需要搞清这两者比较到底是什么。要搞清这个问题,首先我们要理解一个问题,就是我们的对象是如何在内存空间中存放的。

栈内存和堆内存

在JVM中,内存分为

  • 堆内存
  • 栈内存。

java包括两个不同类型的值:

  • 基本数据类型
  • 引用数据类型

当我们申明变量并为该变量赋值时,根据值的类型不同,存储的内存空间位置也不同。

  • 如果变量的类型是基本数据类型(Java的基本数据类型有8种,分别是:byte(位)、short(短整数)、int(整数)、long(长整数)、float(单精度)、double(双精度)、char(字符)和boolean(布尔值)),会在中为其分配内存空间,并直接保存其变量的值。

例如以下代码:

        int a = 10;
        int b = a;
        b = 20;

其值会直接保存在栈中。
在这里插入图片描述

  • 如果变量的类型是一个引用类型,比如当我们创建一个对象(new Object)时,就会在堆内存中为这个对象分配空间,而在栈内存中仅保存对象在堆内存中的地址,也就是说,对象保存在堆空间,但对象的引用保存在栈中。当我们在后续代码中调用的时候对象变量时,用的都是栈内存中的引用。

例如以下代码:

StringBuffer str = new StringBuffer("Helloword");

在这里插入图片描述
还需注意的一点,String是属于引用对象类型,因此,每个String对象也是在堆内存中分配空间,在栈中,只保存String对象的地址引用。

==运算符

==是运算符,在Java中

  • 如果是基本数据类型相比较,则 == 比较的是值
  • 如果是引用类型,则 == 比较的是对象在堆内存中的地址。即判断是否指向同一个内存空间,或者说,是否是同一个对象

比如我们以下面代码为例:

        String a = new String("hello");
        String b = new String("hello");
        System.out.println(a == b);

运行得到的结果是

false

从上面的例子可以看出,虽然a和b这两个String对象的值是相等的,但是由于String类型是引用类型,==运算符比较的是这两个对象的引用,即在堆内存中的地址,也就是说,判断这两个对象是否是同一个对象。
很明显,在上述例子中,a和b不是同一个对象,因此结果为false

equals方法

Java 语言里的 equals方法是Object类的一个成员方法。下面的在类的参考文档中的说明

public boolean equals(Object obj)
指示一些其他对象是否等于此对象。

以下是这个方法的定义

  public boolean equals(Object obj) {
        return (this == obj);
    }

从以上代码中,我们可以看出,Object类的equals方法比较的是两个对象的引用是否相同,即是否是同一个对象。
同学们可能说会奇怪了,那这和==运算符没有不同呀。仅看到这里,的确对于引用类型,比较的都是对象的地址,但是其实equals方法是给开发者去重写的,让开发者自己去定义满足什么条件的两个Object是equal的。

所以我们不能单纯的说equals到底比较的是什么。你想知道一个类的equals方法是什么意思就是要去看定义。

我们以下面的测试代码为例说明说明一下String类的equals方法的执行过程。

        String a = new String("hello");
        String b = new String("hello");
        System.out.println(a.equals(b));

运行结果为

true

下面我们结合String类对equals方法的重写源码分析一下这个测试代码的执行原理。

String类对equals方法进行了重写。以下是String类对equals方法的重写源码:

public boolean equals(Object anObject) {
        if (this == anObject) {
            return true;
        }
        if (anObject instanceof String) {
            String anotherString = (String)anObject;
            int n = value.length;
            if (n == anotherString.value.length) {
                char v1[] = value;
                char v2[] = anotherString.value;
                int i = 0;
                while (n-- != 0) {
                    if (v1[i] != v2[i])
                        return false;
                    i++;
                }
                return true;
            }
        }
        return false;
    }

首先

        if (this == anObject) {
            return true;
        }

如果比较的两个对象是同一个对象,当然返回为真。测试代码中,a和b不是同一个对象,所以,继续比较。

其次,

        if (anObject instanceof String) {

如果两个对象地址引用不同,则看这个要比较的对象是否是String类型的。对象b的类型是String类型,所以,代码继续往下

String anotherString = (String)anObject;//将b向下强转型为String类型,因为入口参数类型是Object类型
int n = value.length;//获得a的长度
if (n == anotherString.value.length) {//如果a的长度和b的长度相同,才继续比较
    char v1[] = value;//将a字符串的值中的每一个字符依次保存到v1字符数组中
    char v2[] = anotherString.value;//将b字符串的值中的每一个字符依次保存到v2字符数组中
    int i = 0;
    while (n-- != 0) {//依次比较v1和v2字符数组中的每个字符的值是否相同,因为现在char是基本数据类型,所以,!=运算符比较的就是值,只要有一个v1和v2中相同次序中的字符有一个不同,则比较结束,并返回为假
        if (v1[i] != v2[i])
            return false;
        i++;
    }
    return true;//如果a 和 b字符长度相同,而且每个字符都相同,则比较结果,返回为真
}

为了方便,我在代码中通过注释来说明。从上可以看出。String的equals方法比较的字符串的值是否相同。
所以,上面的测试代码中,虽然a和b是两个不同的String对象,

  • 判断a==b时,比较的是对象的地址引用,因此比较结果为false
  • 判断a.equals(b)时,由于String类对equals方法进行了重写,比较的是两个字符串的值是否相同,因此,比较结果为true。

相信同学们看到这里,应该就明白了==和equals方法对字符串进行比较时的区别,也明白了,在编写代码时,在什么情况下,该使用equals方法。通常在字符串比较中,我们常使用的还是equals方法。毕竟,我们只是要判断两个字符串的值是否相等。

  • 4
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Java Man

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值