《软件构造》实验三算是所有课程实验中工作量最大的一个,整个实验进行完毕后,我在课程的复习过程中意识到了自己的实验设计中的一个不小的错误。
equal方法是在所有类的父类Object中就给出的方法,但是,在Object中的实现中仅仅是对引用是否等价的一个粗略的判断,可以说几乎没有实用价值,因为我们简单的使用“==”同样可以实现这一功能,因此在大多数类中往往必须要重写此方法来实现我们需要的功能。我们所重写的方法要实现观察等价性或者行为等价性,具体视需求而定。
首先我们来看一下Object的equal方法的源码:
这里可以看到它仅仅实现了简单的对于引用是否一致的判断。这里我们需要着重关注的是它的函数声明:
public boolean equals(Object that);
在这个实验中,我犯的错误类似于这样,我在自己的接口中定义了如下函数声明的方法:
public abstract boolean equals(Vertex a);
不知道大家有没有跟我类似的误解,事实上我在这里所声明的equals函数,没有实现对Object的equals方法的重写,而是阴差阳错的实现了其重载。当然,由于我在实验中保证了所有对于一个接口的实例的equals函数的调用的参数都是这个接口的一个实现的实例,因此可以保证这个阴差阳错的重载还是完美实现了我想要实现的功能的。因为重载的检查是静态的,它在编译阶段就已经确定了每一个函数调用的明确的去向,因此编译器也没有报错。而且由于当时学艺不精,我仅仅在接口Vertex的实现Word类等等的equals函数的声明中使用了@Override注释。所有的这些种种,都保证了我阴差阳错的使用重载完成了重写的目的。。。
那么如何区分对于equals的重写和重载呢,我们举一个例子:
在上述中,第一个是重载,而第二个是重写。最简单的区分策略就是,如果参数的类型是Object的,那么就是重写;如果参数类型是某个你自己的类型,那么就是重载。
那么如何避免呢?
最简单的方式是直接使用Eclipse自动的实现对equals方法和hashCode的添加。。。
其次,一个保险的策略是,即使在你的接口的方法的声明时,也使用@Override注释,主动要求编译器对你的代码执行是否是重写的检测。
当然,最好的方法还是真正的分清楚重写和重载的区别,同时编程时保持一个清醒的大脑,同时养成良好的编程习惯,习惯性的使用@Override和@Overload注释。