请说说==操作符和equals(),从基本数据类型和引用数据类型两个角度谈谈

836 阅读4分钟
  • 本文已参与「新人创作礼」活动,一起开启掘金创作之路。

大家好,我是卷心菜,可以叫我菜菜(名副其实了属于是,哈哈~),大二学生一枚。本篇主要讲解一道java面试题:==操作符和equals()的知识点。如果您看完文章有所收获,可以三连支持博主哦~,嘻嘻。


一、前言

要想理解它们之间的区别,首先要了解一下它们的定义。

  • 当比较引用数据类型时,==比较的是变量的内存地址是否相同,即是否指向同一个对象,是真正意义上的指针操作。
  • equals()比较的是两个对象的内容是否相同,由于所有的类都是继承java.lang.Object类的,所以适用于所有对象,如果没有对该方法进行覆盖的话,调用的仍然是Object类中的方法,而Object中的equals方法返回的却是==的判断。
  • 也就是说==是一个指针操作,用来比较数值相等,而equals则是一个方法,在Object类中equals方法中使用其实就是==,如果子类不重写equals方法,两者则并没有什么不同。

二、源码解析

先看看Object类中的源码: 在这里插入图片描述 从源码中可以看出,两者比较的是地址值。

再来看看String类中的源码: 在这里插入图片描述 从源码中可以看出,String类重写了Object类的equals方法,首先判断两者的地址,如果相等,就直接返回true;不然,就接着判断参数是否是String类型的,如果是,就逐一比较每一个字符内容,最终返回结果。

最后再看看Integer类的源码: 在这里插入图片描述 从源码中可以知道,首先判断参数是否是Integer类型的;如果是,就会调用intValue(),获取该参数的数值,最后两者进行比较;简单的来说,他们最终比较的是数值。


三、基本数据类型比较

对于基本数据类型的比较,只有==操作符,因为基本数据类型不是对象,没有继承Object类,自然也不能重写equals方法。需要注意的是,在使用==操作符时,会出现自动类型转换,看看如下代码:

    public void test1() {
        int i = 10;
        int j = 10;
        double d = 10.0;
        System.out.println(i == j);//true
        System.out.println(i == d);//true
        boolean b = true;
//		System.out.println(i == b);编译就会出现错误
        char c = 10;
        System.out.println(i == c);//true
        System.out.println(c == d);//true
        char c1 = 'A';
        char c2 = 65;
        System.out.println(c1 == c2);//true
    }

四、引用数据类型比较

在引用数据类型的使用过程中,最常用的就是String类了,那么我们就来看看如下代码,尝试自己想一想运行的结果:

    public void test2() {
        String s1 = "hello";
        String s2 = "hello";
        System.out.println(s1 == s2);
        System.out.println(s1.equals(s2));
        
        String str1 = new String("hello");
        String str2 = new String("hello");
        System.out.println(str1 == str2);
        System.out.println(str1.equals(str2));
        System.out.println(s1 == str1);
        System.out.println(s1.equals(str1));
    }

最终的运行结果是:truetruefalsetruefalsetrue

  • 首先看代码的前半部分,s1 == s2的结果是true,是因为字符串的值是final,其值不可变,在内存中只有一份,所以s1和s2的地址值是一样的。
  • 最后看代码的后半部分,因为str1和str2使用了关键字new,即在内存中开辟了两块空间,他们的地址值不相同,所以str1 == str2 的结果是false。

让我们看最后一组代码:

    public void test3() {
        int a = 10;
        Integer b = new Integer(10);
        Integer c = new Integer(10);
        System.out.println(b == c);
        System.out.println(a == c);
        System.out.println(b.equals(c));
        System.out.println(c.equals(a));
    }

运行结果是:falsetruetruetrue

  • 对于a==c这个为什么返回的也是true呢?难道变量a和c存放的内存地址是一样的吗?这显然不正确,毕竟a是基本数据类型,存放的地址是栈中的地址,而c是引用数据类型,存放的地址应当指向对中的地址。这是因为当Integer与int进行==比较时,Integer就会拆箱成一个int类型,所以还是相当于两个int类型进行比较,这里的Integer,不管是直接赋值,还是new创建的对象,只要跟int比较就会拆箱为int类型,所以就是相等的。其实所有的包装类在和其基本数据类型==比较时都会自动拆箱。

五、自定义实现equals方法

那么问题来了,如果我们要自己写的类,也想要重写equals方法该怎么办呢?其实很简单,使用Alt+insert后选择如图即可:在这里插入图片描述 写个代码测试:

    public void test4() {
        Person person1 = new Person("cabbage",20);
        Person person2 = new Person("cabbage",20);
        System.out.println(person1.equals(person2));
    }

如果运行结果返回true,那么恭喜你,成功了~


六、小结

  • 当用equals()方法进行比较时,对类File、String、Date及包装类来说,是比较类型及内容而不考虑引用的是否是同一个对象;是因为在这些类中都重写了Object类的equals()方法。
  • 最后给一个参考答案: 在这里插入图片描述

感谢阅读,一起进步,嘻嘻~