看到这两个词,我以为我掌握了,直到复习时看到ppt中的:
好像哪里有些不对劲!
设想下面的情景:
Person.java
public class Person{
private final String name;
public Person(String name){
this.name = name;
}
public String getName(){
return name;
}
//如果根据名字来判断
//这里的equals()和hashcode()应该怎么写
}
Teacher.java
public class Teacher extends Person{
private final String title;
public Teacher(String name, String title){
super(name)
this.title = title;
}
public String getTitle(){
return title;
}
//如果将name和title作为判断两个对象是否相等的依据
//这里的equals()和hashcode()应该怎么写
}
如果按照ppt中的equals()函数来完成Person类中equals()函数的编写。即:
@Override
public boolean equals(Object that){
if (!(that instanof Person))
return false;
Person t = (Person)that;
return this.name.equals(t.name);
}
如果客户端这样使用:
Person person = new Person("Li");
Teacher teacher = new Teacher("Li","assistant");
boolean ans1 = person.equals(teacher);
//假设已经完成了Teacher.java中的equals()函数
boolean ans2 = teacher.equals(person);
自己按照equals()函数"运行"一遍,将会发现ans1是true,但是ans2是false;这显然是有问题的。
因为equals()决定的应该是一个等价关系,即:满足自反,对称,传递。
那问题出在哪里呢?
我们知道,a instanceof B 是判断a是不是B类或者B类子类的一个实例。则 父类 instanceof 子类 得到true; 子类 instanceof 父类 得到false。
ppt中出现的问题,自己还真的没有注意过。每次写到这里都是靠强大的ide自动生成,但是没有仔细看过到底是什么样的。
看了之后,才发现eclipse自动生成用的是getClass()。
用法 | 功能 |
---|---|
a instanceof B | 如果a是B类的实例,或者a是B的子类的实例,则返回true |
a.getClass()==b.getClass() | 只有当a和b确实是同一个类的实例时,结果才为true |
结合这个表格,好像使用getClass()更合适一些。stanceof的第一个问题。
第二个问题是类似equals()函数中,参数的引用类型和引用指向的对象类型不同时,instanceof判断使用的是哪个?
结合equals()函数可以很简单的知道,其使用的是引用指向的对象类型。
第二个问题,引出第三个问题:当函数参数的形式类型(即参数声明的类型)和参数对象的实际类型不同时,函数内部什么时候使用对象实际类型?什么时候使用参数声明类型呢?
这个问题,类似重写和重载时究竟调用哪个函数的问题。
编译时便可以确定的,使用声明的引用类型;运行时确定的使用对象实际类型。
最后一个困扰多时的问题,为什么重写equls()函数还要重写hashcode()函数?
1.使用hashcode方法提前校验,可以避免每一次比对都调用equals方法,提高效率。
2.保证是同一个对象,如果重写了equals方法,而没有重写hashcode方法,会出现equals相等的对象,hashcode不相等的情况,重写hashcode方法就是为了避免这种情况的出现。