这是我反复看了两遍才理解的部分。其中也不乏参考了他人的微博内容,才大致对这个方法有所理解。
首先我们从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)接下来对所有的需要匹配的域进行匹配就可以了。