Java—equals方法小结

Java—equals方法小结

equals在字面意思上与“==”功能似乎一致,都是“相等”的意思。但在Java实际开发中两者有着很大不同。

1.功能一、字符串的比较

equals方法属于Object类,在该类中我们可以找到源码。
equlas方法在源码中定义如下:

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

从源码可以看出,虽然也用到了“==”运算符,但equals是通过this指针,比较对象的地址值,而并非直接比较数值。
通过下面的一个例子我们可以看出区别:

public class ComPare {
    public static class Sales{
        private String name;
        private boolean Judge1(String s1, String s2){
            //对两个字符串进行equals比较
            if(s1.equals(s2)) return true;
            return false;
        }
        private boolean Judge2(String s1,String s2){
            //对两个字符串进行运算符比较
            if(s1==s2) return true;
            return false;
        }
        private boolean Judge3(Sales s1,Sales s2){
            //对两个字符属性进行运算符比较
            if(s1.name==s2.name) return true;
            return false;
        }
        private boolean Judge4(Sales s1,Sales s2){
            //对两个字符属性进行equals比较
            if(s1.name.equals(s2.name)) return true;
            return false;
        }
        public static void main(String[] args) {
            Sales s1=new Sales();
            Sales s2=new Sales();
            s1.name="Mike";
            s2.name="Mike";
            String s3,s4;
            s3=new String("Nick");
            s4=new String("Nick");
            if(s1.Judge1(s3, s4)) System.out.println("正确!");
            else System.out.println("错误!");
            if(s1.Judge2(s3, s4)) System.out.println("正确!");
            else System.out.println("错误!");
            if(s1.Judge3(s1, s2)) System.out.println("正确!");
            else System.out.println("错误!");
            if(s1.Judge4(s1, s2)) System.out.println("正确!");
            else System.out.println("错误!");
        }
    }
}

运行结果如下:

正确!
错误!
正确!
正确!

由第一、第二个输出结果可见,由于字符串s1和字符串s2的数值相等,但存放在内存中的地址值不等,故当运用到“”运算符时,boolean类型会返回False。
那么为什么字符串变量作为对象的属性时,“
”和equals的返回值又会相同呢?这便涉及到了JVM中内存管理的问题,二者在存放时位于JVM的同一块内存区域,故地址值相等。在此不作赘述。
同时还需注意的是:如果是基本类型比较,那么只能用==来比较,不能用equals。即如果这么用的话,编译是无法通过的。

一个需要注意的“BUG”

我们来看经典《Java编程思想》中的一段代码:

class Value {
    int i;
}
public class EqualsMethod2 {
    public static void main(String[] args) {
        Value v1 = new Value();
        Value v2 = new Value();
        v1.i = v2.i = 100;
        System.out.println(v1.equals(v2));//flase 
        System.out.println(v1 == v2);//false 
    }
}

为什么第一个输出False呢?
原来,如果在新类中被覆盖了equals方法,在此确实是用来比较内容的。但是在上面的例子中类Value并没有覆盖Object中的equals方法,而是继承了该方法,因此它就是被用来比较地址的,又v1和v2的所指向的对象不相同,故两行输出结果均为false。

2.功能二、方法重载

我们再在ide中直接调用equals方法:

@Override
    public boolean equals(Object obj) {
        return super.equals(obj);
    }

由于Object类可以说是整个JDK中“祖宗”级别的存在,对于“==”号,我们没办法像C++那样通过运算符重载来实现重写。但由于equals是一个方法,我们可以通过重写实现方法的重载。
这也引出了equals的第一个功能:
方法可重载
下面我们来举一个Java实例:
比如我们要判断两个学生是否是同一个,由于存在着同名的情况,因此我们需要同时对学生的学号进行判断:

@Override
    public boolean equals(Object obj) {
        //此处采取了工厂模式创造对象
        if (this==obj) return true;
        else if (obj==null||getClass()!=obj.getClass()) return false;
        Stu stu=(Stu) obj;
        return id == stu.id && (Objects.equals(name,stu.name));
    }

运行整个程序:

扫描二维码关注公众号,回复: 9749365 查看本文章
import java.util.Objects;

public  class Stu{
    private String name;
    private int id;
    @Override
    public boolean equals(Object obj) {
        //此处采取了工厂模式创造对象
        if (this==obj) return true;
        else if (obj==null||getClass()!=obj.getClass()) return false;
        Stu stu=(Stu) obj;
        return id == stu.id && (Objects.equals(name,stu.name));
    }
    public boolean Judge(Stu stu1,Stu stu2){
        if (stu1.equals(stu2)) return true;
        else return false;
    }
    public static void main(String[] args) {
        Stu stu1=new Stu();
        Stu stu2=new Stu();
        Stu stu3=new Stu();
        stu1.id=101;
        stu2.id=102;
        stu3.id=101;
        stu1.name="James";
        stu2.name="James";
        stu3.name="James";
        if(stu1.Judge(stu1, stu2)) System.out.println("是同一个学生");
        else System.out.println("不是同一个学生");
        if(stu1.Judge(stu1, stu3)) System.out.println("是同一个学生");
        else System.out.println("不是同一个学生");
    }
}

程序运行结果:

不是同一个学生
是同一个学生

可见,我们可以通过类似重载运算符的方法,对equals类进行重写,从而满足我们的各种功能需要。

equals重写的限制

通过查阅JDK,我们可以发现,equals在重写时是有限制的(在此偷个懒,抠的是别人翻译好的图 ):

在这里插入图片描述

拓展:equals重写与hashcode

由于hash在Java内存管理和数据查询中起着非同一般的作用,因此每当我们提到地址时,我们便不得不提到hash和hashcode。
关于Java中的hash原理、运用,在此不是本文的重点。在此只讨论hashcode和equals的关系。
由于hashcode是由数值经过hash算法得来的,所以有这么一条结论:
equals相等,hashcode相等;但hashcode相等,equals不一定相等
且我们还需要注意:
equals重写后,hashcode方法通常也需要重写
此结论在此亦不作赘述,大家可在运用HashMap时体会。

总结

1.equals是Object类的成员方法,本身比较的是“值”,而“==”运算符比较的是地址。但在使用时,需要把握好类的继承与覆盖的区别;
2.equals的一大好处在于可被重写,但在与hashcode结合运用时需要注意最好同时也重写hashcode。

发布了29 篇原创文章 · 获赞 18 · 访问量 4002

猜你喜欢

转载自blog.csdn.net/weixin_44522586/article/details/104146347