Java 中 == 与 equals() 方法的区别

本文详细解析了Java中==与equals()的区别及其工作原理,包括它们如何应用于基本数据类型和对象,特别是针对String类型的特殊行为进行了深入探讨。

== 与 equals() 都有比较两者是否相等的意思, == 用于比较两个操作数的值是否相等,equals() 默认是对 == 的封装,通常需要自定义重写来定义不同的相等条件

关系操作符 ==

== 属于关系操作符,关系操作符用于比较两个操作数的值之间的关系,在 Java 的内存结构中,基本数据类型是直接存放在操作数栈中的,而对象则是存放在堆内存中,在操作数栈中存放的是堆中对象的引用地址。对于基本数据类型,其操作数的值就是基本数据类型的值,而对于对象,其操作数的值是对象的引用地址,因此在对基本数据类型使用 == 进行比较时,能够直接比较两者的值,得到想要的结果,而对象如果使用 == 进行比较,比较的就是对象的引用地址,这样即使两个对象的内容完全相等,由于地址不相等,得到的就不是想要的结果了

 public static void main(String[] args) {
        Integer n1 = new Integer(11);//创建 Integer 类的对象
        Integer n2 = new Integer(11);
        System.out.println(n1 == n2);
        int n3 = 11;//创建 int 类型数据
        int n4 = 11;
        System.out.println(n3 == n4);
    }

输出结果:

false
true

从运行结果中分析,n1 和 n2 是Integer 类的对象,因此在操作数栈中存放的是他们的引用地址,使用 == 比较时,地址不相同,因此结果为 false,而 n3 和 n4 是 int 类型数据,操作数栈中存放的就是 11 这个值,因此返回结果为 true

值得注意的是 String 类型的数据,按照上面描述的,String 不属于基本数据类型,也就是他在操作数栈中存放的也是引用地址,那按理说对两个具有相同值的 String 类型数据使用 == 比较,结果也应该是 false,然后事实并不是这样:

 public static void main(String[] args) {
        String s1 = new String("str");//创建 String 类对象
        String s2 = new String("str");
        System.out.println(s1 == s2);
        String s3 = "str";
        String s4 = "str";
        System.out.println(s3 == s4);
    }

输出结果:

false
true

从结果中分析,对于 s1 == s2 返回 false 很好理解,因为 s1 与 s2 是两个对象,在操作数栈中存放的是他们的引用地址,两者地址不相等,所以返回 false。

补充一下,在使用 String s1 = new String(“str”) 时,实际上是创建了两个对象,一个是在字符串缓冲池中创建一个”str”对象,另一个是在堆上创建一个指向 “str” 的String 类型对象,而这里的 s1 和 s2 都指向的是堆上的对象。更多关于 String 的内容可以参考 这篇关于 String 的文章这篇关于 String 中的 intern 方法的文章

对于 s3 == s4 的返回结果,会有一点点疑问:既然 String 类型的 s3 和 s4 是引用类型,那在操作数栈中存放的是他们的引用地址,为什么返回结果为true,难道他们的引用地址相等?答案是:是的。这是因为在程序运行时,会创建一个字符串缓冲池,在创建String 类型数据 s3 的时候,首先会从字符串缓冲池中寻找具有相同值的对象,如果有就直接将 s3 指向这个已有的对象,如果没有才新建一个,这样,显然执行 s3 == “str” 时,字符串缓冲池中是没有相同值的对象,因此需要新建一个 “str” 对象,而在执行 s4 == “str” 时,检查字符串缓冲池,发现已经有一个 “str” 对象了,于是 s4 直接指向这个 str,到此,s3 和 s4 指向的就是同一个对象了,也就是说他们在操作数栈中存放的对象引用地址是同一个,当然就相等了。

Object 中的方法 equals()

由于 == 只能比较两个操作数的值之间的关系,那如果想要比较两个对象的值之间的关系呢,这时就需要用到 equals() 方法了,equals() 是 Object 类中的方法,在 Java 中,Object 类是所有类的父类,所以只要是 java 中的类,都有 equals() 方法。在 Object 类中的 equals() 方法如下:

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

可以看到,equals() 默认其实也是使用 == 来进行比较的,即:equals() 方法默认比较两个对象的地址,对于特定的类,需要重写 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;
    }

从 String 类中的 equals() 方法可以看出,判断两个字符串是否相等需要满足的条件是:

  • 两者的地址相同,即两者是同一个对象

或者

  • 两者的长度相同并且两者中每一个字符都相同

因此,equals() 方法是需要根据特定的类重写特定的逻辑,通常同时需要重写 hashCode() 方法,hashCode() 方法返回一个与对象的地址相关的值,对于 Object 中默认的 hashCode() 方法,仅当两个对象的地址相等时,他们的 hashCode() 返回值才相等。在 String 类中,重写了 hashCode() 方法,使得 hashCode() 方法不再与地址相关,这样做是为了保证用 equals() 比较返回为 true 的两个对象,他们的 hashCode() 返回值也是根据相关逻辑得到的一个相同的值

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值