// 先看Object类中的equals方法
class Object {
public boolean equals(Object obj) {
// 比较当前对象(即调用equals方法的那个对象)和方法参数接收的obj对象是否相等。
// 默认认比较的是地址值,也就是说比较的是两个引用是否指向同一个对象。
return (this == obj);
}
}
// 所有类都直接或者间接继承自Object,我们分析String类的equals
class String extends Object { // 此处的extends Object写与不写都有
// 此处的equals是重写父类Object的
public boolean equals(Object obj) {
// 重写之后比较的是当前字符串(即调用equals方法的那个字符串对象)和方法参数接收的obj对象是否相等。
// 但不再比较地址值,比较的是两个字符串的实际字符是否一样。
/*
通过分析源码我们发现字符串重写equals方法实现的比较过程如下:
为了提高效率:
先判断两个对象地址值是否一样。如果一样,直接返回true,它们的字符值肯定一样。因为引用指向了同一个对象。
为了程序的健壮性:
再判断传递过来的obj参数是否是String类型的参数,如果不是,没必要比较了,肯定是false。
判断实际字符值:
然后,将两个字符串都转化成字符数组。依次比较数组相同索引处的两个字符是否相同。
一旦发现有一个不同,返回false。全部相同才返回true。
*/
return xxx;
// 简而言之,String类重写equals方法实现了两个字符串真正字符值的比较。
}
}
// 然后再看我们自定义的类
class Student { // 此处也包含一个默认的 extends Object
private String name;
private int age;
// getters and setters
// 我们也想重写equals方法实现两个Student对象的实际属性值的比较。所以我们也模仿String类的三步。
public boolean equals(Object obj) {
// 为了提高效率,如果两个Student对象的地址值一样,肯定true
if (this == obj) {
return true;
}
// 为了程序的健壮性,判断参数obj是否是Student类的对象(或实例)
if (!(obj instanceof Student)) {
// 参数obj不是Student类型的,没必要再比较了,并且也不能把obj向下转型成Student类型了。
return false;
}
// 上述两个条件都不满足,向下转型(因为父类引用不能使用子类特有的属性和行为),比较两个对象具体的属性值
Student stu = (Student) obj;
return this.age == stu.age && this.name.equals(stu.name);
/*
解释 this.name.equals(stu.name)
this.name -- 表示调用方法的Student对象的name属性,它返回的是一个字符串类型。
stu.name -- 表示参数接收的Student对象的name属性,它返回的也是一个字符串类型。
是String类型,那么它就可以调用String类的功能,而String的equals方法恰好已经实现了两个字符串具体值的比较。
所以this.name.equals(stu.name),就是在比较两个对象的name属性值是否一样。
这的equals与我们重写的Student类的equals没有关系,只不过我们重写的时候用到了String类的这个方法而已。
如果仍有疑惑,看下面:
String s1 = this.name; -- 将字符串类型的this.name赋值给引用s1
String s2 = stu.name; -- 将字符串类型的stu.name赋值给引用s2
boolean b = s1.equals(s2); -- 调用String类的equals方法比较s1和s2这两个字符串的真正值
将上面三行代码合并为一行不就是 this.name.equals(stu.name)
*/
}
}
|
|