谈谈==和equals()那些事情

17 篇文章 0 订阅

一转眼好几天都没有写些什么东西了,今天正好周末,我们就聊聊==和equals使用时的那些事情吧。

==和equals的区别是什么?

有一点Java基础的人都会回答,==是基于内存地址的比较,equals()是基于对象内容的比较。

但事情就真的就这么简单吗? 上一段测试代码

public class Animal {
    public String name;
    public Integer age;
    public Animal() {
    }
    public Animal(String name, Integer age) {
        this.name = name;
        this.age = age;
    }
}
    public static void main(String[] args) {
        Animal animal1 = new Animal("1", 1);
        Animal animal2 = new Animal("1", 1);
        if (animal1.equals(animal2)) {
            System.out.println("==");
        } else {
            System.out.println("!=");
        }
    }

运行截图截图
这里写图片描述

可能很多人都开始觉得自己眼睛花,觉得运行逻辑有问题,但事实就是这样,无从辩驳。即使是事实,我们就应该像一个学者一样探究客观事实背后的真相,这里就牵涉到Java的一些隐藏的世界观。

在Java里面,如果没有显示的继承(extends)某个类,那么就会默认继承(extends)Object这个超类(父类、基类),这是由JVM保证的强制规则(PS:网上的一些文章说的是编译器保证,这个刚才亲自测试了一下,反编译.class文件,没有看到默认继承的,版本:java version “1.8.0_161”,Java(TM) SE Runtime Environment (build 1.8.0_161-b12),Java HotSpot(TM) 64-Bit Server VM (build 25.161-b12, mixed mode),这个可以自己测试),在自己不重写(Override)的情况下,会默认调用父类对应的方法。

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

在Object里面,equals()就是直接用的==判断。

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()是基于内容来比较的说法也源自这里。可以明显的看出,equals()是重写(Override)过的,也可以看出为什么说是基于内容来比较。在Java里面很封装类都自己重写了equals(),所以给人造成一种错觉,==是基于地址比较,equals是基于内容比较。这种说法不能说错,但也算不上正确。虽然很多类都重写的equals(),不过有部分封装类比较的时候会出现意料之外情况,比如:Integer、Enum一类。这个时候应该基于对应的版本去看源码实现吧,我一直觉得阅读源码才是最快的理解方式。

基于上面的讲述,你对==和equals()应该有所了解,对使用这两者的场合应该有着更清晰的定义,要实现自定义封装数据类型的比较,需要重写自己的equals()。这点很重要,不然还是会默认调用==。

现在讲讲重写(Override)equals()的注意事项:
1、自反性:对于任何非空引用值 x,x.equals(x) 都应返回 true。
2、对称性:对于任何非空引用值 x 和 y,当且仅当 y.equals(x) 返回 true 时,x.equals(y) 才应返回 true。
3、传递性:对于任何非空引用值 x、y 和 z,如果 x.equals(y) 返回 true,并且 y.equals(z) 返回 true,那么 x.equals(z) 应返回 true。
4、一致性:对于任何非空引用值 x 和 y,多次调用 x.equals(y) 始终返回 true 或始终返回 false,前提是对象上 equals 比较中所用的信息没有被修改。
5、对于任何非空引用值 x,x.equals(null) 都应返回 false。

上述所说是在Java规范中要求的,只是一种强制,没有强制要求。如果不遵守这些规范,使用equals()会出现一些意想不到的错误,官方没有给出具体说明。程序开发是一个团队活动,该遵守的规范还是应该遵守的。

两者最本质的区别还是:==是一种操作符运算,而equals()是一个类方法的。

如有疑问,欢迎留言!

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值