Java基础-equals方法

Object类中的equals方是用来判断一个对象等于另一个对象,至于这个等于的条件需要,比如说,String类的equals相等的条件就是字符串的内容必须相同,equals方法返回的值才为true。所以在我们在自己定义的类中,equals的重写是常见的!这里主要展示equals的特性和equals的正确写法,至于equals方法具体的含义这里不介绍!

1. 举一个例子

在这介绍其他的,我们先来看看正确的写法

public class Animal {
    private String name = null;

    public Animal(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
    @Override
    public boolean equals(Object obj) {
        if(this == obj) {
            return true;
        }
        if(obj == null) {
            return false;
        }
        if(this.getClass() != obj.getClass()) {
            return false;
        }
        Animal animal = (Animal) obj;
        //return this.name.equals(animal.name);
        //这个方法只在JDK7及其以后才有的
        //这个方法能够保证两个name其中只有一个为null的话,返回的false
        //如果两个都为null的话,返回的是true
        //如果两个都不为null的话,具体看情况
        return Objects.equals(this.name, animal.name);
    }
}

从上面的代码中我们看到是,Animal类的equals方法判断的相等条件是name是否为相同。说实话,判断的条件非常的简单,但是我们的代码写的非常复杂。可能有人会这样写的:

    public boolean equals(Object obj) {
        if(! (obj instanceof Animal)) {
            return false;
        }
        Animal animal = (Animal) obj;
        return this.name.equals(animal.name);
    }

实际上,上面的代码是有很大的问题,至于有什么问题,待会再说!这里我们来解释一下正确equals方法写的代码:

1. this == obj, 毫无疑问,如果两个对象的内存都是相同的话,那么肯定是同一个对象了。
2. this == null, 同样的话,如果传进来的对象是null的话,肯定为false。
3. this.getClass == obj.getClass, 这个条件可能让人有点疑惑。我来解释一下,getClass是获得当前的对象的Class对象,至于什么是Class对象,这里不解释,需要的记得是:同一类的所有对象的获得的Class对象都是同一个Class对象,也就是说,这里的this如果obj不属于同一个类的,那么肯定为false。

那么这种写法有好处呢,等我把在列出一个类的代码再说吧!

public class Dog extends Animal{
    private int age = 0;
    public Dog(String name, int age) {
        super(name);
        this.age = age;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public boolean equals(Object obj) {
        if(!super.equals(obj)) {
            return false;
        }
        Dog dog = (Dog) obj;
        return this.age == dog.age;
    }
}

我们发现Dog类继承于Animal类,并且重写了父类的equals方法。在Dog类中equals方法,我们先来判断了这两个对象是否是相等的,其次再比较了age是否相同的。其中先调用了父类的equals来判断,再来判断子类本身的条件,这种方法有几个好处:

1. 符合继承的特性,当且仅当他们通过父类equals才有可能判断子类的条件,因为如果不判断父类的equals的话,当父类的equals返回的是false,但是通过调用子类的equals却返回true。这个根本不符合面向对象的特性,实际点,如果两个儿子老爸都不相同的话,儿子怎么可能相同!
2. 避免了obj是Dog类的子类(虽然这里Dog类没有子类)。因为这里,我们先来调用父类的equals,父类的equals方法中:this.getClass() == obj.getClass 会帮助我们判断这两个类是否是同一个类。按照我们以往的写法,使用instanceof关键字来进行判断的是有很大的问题的,如果this是Dog类的对象,但是obj的实际类型是Dog子类的对象,如果使用 obj instanceof Dog 这个返回的肯定为true,如果通过了我们这个判断语句,最后来判断我们的age。实际上,这两个对象肯定不是同一个对象,所以最后用age来判断是有问题的。至于这个问题的详细解释,待会还会提及!

2. equals方法的特性

上面留了一些伏笔,这里将详细的解释,但是在解释之前,我们先来看看equals方法的特性:

1. 自反性:对于任何的非空对象,x.equals(x)返回肯定为true。

2. 对称性:对于任何两个非空对象x、y,如果x.equals(y)返回的是true,那么y.equals(x)返回的是肯定也为true。

3. 传递性:对于任何三个非空对象x、y、z,如果x.equals(y)为true,并且y.equals(z),那么x.equals(z)肯定也为true。

4. 一致性:如果对象x和对象y没有发生任何变换的话,反复调用y.equals(x)应该返回的是一样的结果。

5. 对于任意非空对象x,x.equals(null)应该返回的是false。

针对这些特性,我们拿一个特性来解释为什么使用instanceof关键字来进行判断有很大的问题。

假设,记住这里是假设:如果Animal类的equals方法和Dog类的equals方法使用的是instanceof关键字来判断的,也就是下面的代码:

Animal类的equals方法:
    @Override
    public boolean equals(Object obj) {
        if(!(obj instanceof Animal)) {
            return false;
        }
        Animal animal = (Animal) obj;
        return Objects.equals(this.name, animal.name);
    }
Dog类的equals方法:
    @Override
    public boolean equals(Object obj) {
        if (!(obj instanceof Dog)) {
            return false;
        }
        Dog dog = (Dog) obj;
        return this.age == dog.age;
    }
然后我们在main方法里面这么写:
    public static void main(String[] args) {
        Animal a1 = new Animal("pby");
        Dog d1 = new Dog("pby", 21);
        System.out.println(a1.equals(d1));
        System.out.println(d1.equals(a1));
    }

我们可以看到的是第一个结果返回的true,但是第二个返回的false。这个就有问题了,不符合equals方法的对称性。

我们来分析一下,当a1.equals(d1)时,调用的Animal类中的equals方法,这个方法对name进行判断,首先d1 instanceof Animal 肯定为true,因为Dog类是Animal的子类,所以if条件没有屏蔽掉d1,由于两个对象的name是相同的,所以返回值是true,但是真正的结果是false,因为他们不属于同一个类!至于第二个为什么是false,这里将不在解释了!

然后我们回来看正确写法,this.getClass == obj.getClass这个判断就能够将我们的d1屏蔽掉!

时间: 2024-11-06 04:00:02

Java基础-equals方法的相关文章

1.28 Java基础总结 ①方法重载②构造方法

1.28 Java基础总结 ①方法重载②构造方法 一.方法的重载在同一个类中,方法名相同,形参列表不同访问修饰符.返回类型和是否重载无关:按顺序对应的形参列表类型不同即可 二.构造器在类创建一个实例时被调用,构造方法只能用new关键字调用目的:初始化实例,初始化类属性(0,0.0,null,false)无返回值,和类名一致,用来构造对象作用:为对象分配内存, 创建并初始化成员变量(通过类创建,所以可以在static方法中调用构造方法) 返回引用,引用.属性:引用.方法(所以无返回值) 三.构造方

Java基础02 方法与数据成员(转载)

对象中的数据成员表示对象的状态.对象可以执行方法,表示特定的动作. 此外,我们还了解了类(class).同一类的对象属于相同的类型(type).我们可以定义类,并使用该定义来产生对象. 调用同一对象的数据成员 方法可以调用该对象的数据成员.比如下面我们给Human类增加一个getHeight()的方法.该方法返回height数据成员的值: public class Test{    public static void main(String[] args){        Human aPer

Java的equals方法的使用技巧

Java的equals方法的使用技巧 1.业务场景: 在某个社交软件中,要求每个用户的用户名(name)必须独一无二,那么在每次增加新用户的时候,都要对该用户的注册名进行判断,如果当前用户名已经被占用,则无法为该用户创建账号,只能要求该新用户重新选择设定用户名. 2.解决思路: 考虑到这里比较的每一个用户这样的对象,而其的等价判断标准是name,因此我们可以考虑使用object类自带的equals()方法对其进行比较,其中在方法体中以判断标准name进行返回. 补充:对于不同的数据类型,其比较方

java重写equals方法(重点讲解)

为什么equals()方法要重写? 判断两个对象在逻辑上是否相等,如根据类的成员变量来判断两个类的实例是否相等,而继承Object中的equals方法只能判断两个引用变量是否是同一个对象.这样我们往往需要重写equals()方法. 我们向一个没有重复对象的集合中添加元素时,集合中存放的往往是对象,我们需要先判断集合中是否存在已知对象,这样就必须重写equals方法. 怎样重写equals()方法? 重写equals方法的要求: 1.自反性:对于任何非空引用x,x.equals(x)应该返回tru

关于java重写equals方法

首先为什么要重写equals方法呢? 这可能是我们比较关心的一个问题. 我个人的理解是,因为java Object类中自带的equals方法可能往往功能不够用. 所以我们需要重写他,给他自定义一些功能或者说是拿去特定的地方去用. 比如说我们要比较两个对象中的是否相同.我们就要拿这2个对象中的属性是否相同. 但是Object类中提供的方法没有提供这样的功能,所以我们这个时候就需要重写. 我们来看下例子(附带一些本人的理解,只做参考,欢迎批评指正.) 1 public class EqualsOve

java重写equals方法需要注意的几点

为什么equals()方法要重写? 判断两个对象在逻辑上是否相等,如根据类的成员变量来判断两个类的实例是否相等,而继承Object中的equals方法只能判断两个引用变量是否是同一个对象.这样我们往往需要重写equals()方法. 我们向一个没有重复对象的集合中添加元素时,集合中存放的往往是对象,我们需要先判断集合中是否存在已知对象,这样就必须重写equals方法. 怎样重写equals()方法? 重写equals方法的要求:1.自反性:对于任何非空引用x,x.equals(x)应该返回true

Java基础02 方法与数据成员

作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明.谢谢! 在Java基础01 从HelloWorld到面向对象,我们初步了解了对象(object).对象中的数据成员表示对象的状态.对象可以执行方法,表示特定的动作. 此外,我们还了解了类(class).同一类的对象属于相同的类型(type).我们可以定义类,并使用该定义来产生对象. 我们进一步深入到对象.了解Java中方法与数据成员的一些细节. 调用同一对象的数据成员 方法可以调用该对象

Java的equals方法实现及其细节

判断两个对象是否等价,是OOP编程中常见的需求(下面围绕Java来进行阐述). 考虑这样几种情况:通过某个特征值来判断两个对象是否"等价",当这两个对象等价时,判断结果为true,否则结果为false. 当然,这里的"特征值"不会只是简单的"对象引用",事实上,Object类(Java的"对象世界"的根)中实现的equals方法,就是把"特征值"设定为"对象引用"来进行判断等价性的,因此

java toString equals方法

1.public class C {public String toString() {//重写了父类的方法 此处的父类是object 默认都继承了return "haha";} } public class Test_toString {public static void main(String[] args){C cc=new C();System.out.printf("%s",cc.toString());//若没重写 输出的就是aa对象在栈堆里的地址的十