关于JAVA核心技术(卷一)读后的思考(equals方法的讨论)

Posted zzuzhouxiang

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了关于JAVA核心技术(卷一)读后的思考(equals方法的讨论)相关的知识,希望对你有一定的参考价值。

这是我反复看了两遍才理解的部分。其中也不乏参考了他人的微博内容,才大致对这个方法有所理解。

首先我们从Object类开始说起,

书中已经说了Object类是Java中所有类的始祖,在Java中的每个类都是由他扩展而来的,但在现实使用中并没有要求写出。如果一个类并没有明确指出超类,Object就是被认为是这个类的超类。

可以用Object类型的变量引用任何类型的对象:

Object obj = new Employee("Harry Hacker",35000);

正如昨天的博文所提到过的,Object只是用作各种值的通用持有者,是无法对其中的内容进行操作的,如果想要对其进行操作的话,需要弄清对象的原始类型,并对其进行类型转换。如:Employee e = (Employee)  obj;

 

 

 

知道这些我们就可以来提一提equals方法了;

在java中,对于基本数据类型,判断它们是否相等是通过“==”来进行判断的,而equals方法是用于检测一个对象是否等于另外一个对象的。在Object类中这个方法是判断两个对象是否具有相同的引用。但这种判断在大部分情况下是没有意义的,因为我们经常要检测的是两个对象状态的向邓姓,如果两个对象状态相等了,就表示相等了。

例如,若两个雇员对象的姓名、薪水和雇佣日期都一样,就认为它们是相等的。

其中equals代码实现如下:

public class Employee{

……

public boolean equals (Object otherObject){

  if(this==otherObject)                                                      //首先判断是否具有相同的引用

     return true;

if(othterObject==null)                                                    //判断显式参数是否为空

   return false;

if(getClass()!=otherObject.getClass())                         //判断二者是否属于相同的类

  return flase;

Employee other=(Employee)otherObject;                     //把显式参数类型转换成相同类型,这样可以对其进行操作

  return name.equals(other.name)&&salary==other.salary&&hireDay.equals(other.hireday);

    }

}

 

 

相等测试与继承

在上面的代码,我们会想到一个问腿,若隐式参数和显示参数不属于同一个类,equals方法将如何处理?

这时候我们就会引出另一个关键字instanceof,当时我看书的时候是不能理解书上想表达的意思。因为instanceof这个关键字可能是第一次出现在书本上,而我在前面的学习中并没有印象,所以我当时就是网上查阅资料,至于正确性我也不敢保证,但是我如果按照他的解释是可以解释的通的,所以我先在这里列出来:

java 中的instanceof 运算符是用来在运行时指出对象是否是特定类的一个实例。instanceof通过返回一个布尔值来指出,这个对象是否是这个特定类或者是它的子类的一个实例。

了解这个关键字之后我们还要知道Java语言贵伐要求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)应该返回同样的结果。

5)对任意非空引用x,x.equals(null)应该返回false。

了解这些之后,就会出现一个问题:

若出现e.equals(m),这里的e是一个Employee对象,m是一个Manager对象,并且两个对象具有相同的姓名,薪水和雇佣日期。

这样的话,如果在Employee.equals中用instanceof进行检测,则会返回出,而反过来调用因为对称性的原因,也应该返回true。所以我们就给出一个完美的equals方法的建议:

1)显式参数命名为otherObject,稍后需要将它转换成另一个叫做other的变量。

2)检测this和otherObject是否引用同一对象:

if(this==otherObject)

  return true;

3)检测otherObject是否为null,如果为null,返回false。

4)比较this和otherObject是否属于同一个类。如果equals的语义在每个子类中有所改变,如果equals的语义在每个子类有所改变,就使用getClass()检测。

if(getClass()!=otherObject.getClass())

  return  false;

这里有必要解释一下getClass()方法的原理了:

技术分享图片

 

 即返回:

表示此对象的运行时类的类对象。

同时我还举了例子以此说明:

技术分享图片

 

技术分享图片

 

public class GetclassDemo {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Employee e=new Employee();
        Manager m=new Manager();
        e.setId(1);
        m.setId(1);
        
    
        
        if(m.getClass()==e.getClass()) {
            System.out.println("yes");
        }else
        {
            System.out.println("no");
        }
        if(m.equals(e)) {
            System.out.println("yes");
        }else
        {
            System.out.println("no");
        }
        if(m instanceof Employee) {
            System.out.println("yes");
        }else {
            System.out.println("no");
        }


    }

}
结果:

class com.java.getclassDemo.Employee
++++++++++
class com.java.getclassDemo.Manager
++++++++++
class com.java.getclassDemo.Manager
no
no
yes

下面来分析一下,第一二行是初始化Employee时调用的getClas()方法

此时为Employee,

第三四排为调用子类Manager的构造函数时同时会调用其超类的构造函数,再调用自己的getClass();

而后面第二个no表示二者表示的状态并不一样,而第三个yes表示m确实为Employee的子类,也从侧面证明上文说到的方法是正确的。  

 

 

回到正文。接下来时如果所有子类拥有同一语义,则可以用instanceof检测。

5)将otherObject转换为相应的类类性变量。

这里的类型转换我觉得有个博主解释的特别好

https://blog.csdn.net/heidou369/article/details/80414904

但是对于getClass()我并不赞同他的看法,在这里我也不知道谁对谁错

6)接下来对所有的需要匹配的域进行匹配就可以了。

 













































以上是关于关于JAVA核心技术(卷一)读后的思考(equals方法的讨论)的主要内容,如果未能解决你的问题,请参考以下文章

关于JAVA核心技术(卷一)读后的思考(内部类的讨论)

关于JAVA核心技术(卷一)读后的思考(用户自定义类,静态域和静态方法的思考以及方法参数)

关于JAVA核心技术(卷一)读后的思考(泛型数组列表的讨论)

关于JAVA核心技术(卷一)读后的思考(接口的基本知识的讨论)

关于JAVA核心技术(卷一)读后的思考(对象与类,日历的构造)

关于JAVA核心技术(卷一)读后的思考(lambda表达式的讨论)