以下是翁恺老师的示例代码的一部分:
package dome;
public class CD extends Item{
private String artist;
private int numofTracks;
// private int playingTime;
// private boolean gotIt=false;
// private String comment;
public CD(String title, String artist, int numofTracks, int playingTime, String comment) {
super(title,playingTime,false,comment);
// this.title = title;
this.artist = artist;
this.numofTracks = numofTracks;
// this.playingTime = playingTime;
// this.comment = comment;
}
@Override
public String toString() {
return "CD{" +
"artist='" + artist + '\'' +
", numofTracks=" + numofTracks +
"} " + super.toString();
}
@Override
public boolean equals(Object obj) {
//public boolean equals(CD obj) 不加@Wverride 也可以成功运行,但这并不是重写Object类的equals方法,而是重载(overload)了一个新的方法
CD cc=(CD)obj;
return artist.equals(cc.artist);
}
public static void main(String[] args) {
CD cd=new CD("a","b",2,2,"...");
CD cd1=new CD("a","b",2,2,"...");
System.out.println(cd.equals(cd1));
// cd.print();
// String s="aa"+cd;
// System.out.println(s);
}
public void print() {
System.out.print("CD:");
super.print();
System.out.println(":"+artist);
// System.out.println("CD"+":"+title+":"+artist);
}
}
分析下面这段代码:
重写
@Override
public boolean equals(Object obj) {
CD cc=(CD)obj;
return artist.equals(cc.artist);
}
- @Override:
@Override表示重写 注解使得 Java 编译器可以执行一个安全检查。如果你标注了一个方法为 @Override,但这个方法实际上并没有重写任何超类中的方法,编译器将报错。
-
public boolean equals(Object obj) {...}: 通常要在两个对象上调用此方法,如cd1.equals(cd2)
-
CD cc=(CD)obj;: 将传入的Object类型的对象强制转换为CD类型
-
return artist.equals(cc.artist); : this.artist指的是cd1.artist,cc.artist指的是cd2.artist
- 重写:
Java中,equals()方法用于比较两个对象是否等效。在这里CD类中重写equals()方法是为了定义CD对象之间的等价性。
方法的重写是基于类层次结构的
- 如果子类重写了父类的方法,当通过子类的实例调用该方法时,将调用子类的重写版本。
- 如果其他子类没有重写该方法,当通过这些子类的实例调用该方法时,将调用父类的版本。
class Item {
public void print() {
System.out.println("Item print");
}
}
class CD extends Item {
@Override
public void print() {
System.out.println("CD print");
}
}
class DVD extends Item {
// DVD 没有重写 print 方法
}
public class Main {
public static void main(String[] args) {
Item item = new Item();
CD cd = new CD();
DVD dvd = new DVD();
item.print(); // 输出: Item print
cd.print(); // 输出: CD print
dvd.print(); // 输出: Item print
}
}
重载:
public boolean equals(CD obj){
return artist.equals(obj.artist);
}
区别:
-
重写 vs 重载:
- 重写:方法签名(包括方法名、参数类型和顺序)必须完全匹配父类的方法。目的是在子类中提供父类方法的具体实现。
- 重载:方法名相同但参数列表不同。目的是在同一个类中提供不同参数列表的同名方法。
-
Object
类的equals
方法签名:Object
类的equals
方法签名是public boolean equals(Object obj)
。如果你定义public boolean equals(CD obj)
,它并没有重写Object
类的equals
方法,因为参数类型不同。这个方法是一个新的方法,只是与equals
名字相同,但并不会覆盖Object
类的equals
方法。 -
调用行为:
- 如果你在
main
方法中调用cd1.equals(cd2)
,而没有重写Object
类的equals
方法(即public boolean equals(Object obj)
),它将调用Object
类的默认实现,而不是你定义的public boolean equals(CD obj)
方法。 - 为了使
equals
方法在所有场景下都能正常工作,特别是在集合类(如HashSet
、HashMap
)等需要比较对象相等性的地方,你必须重写Object
类的equals
方法。
- 如果你在
方法调用解析
在Java中,方法的调用是基于静态类型解析的(也就是编译时的类型)。cd1.equals(cd2)
会首先查找最匹配的方法签名。如果存在一个更具体的重载版本(例如 equals(CD obj)
),编译器会选择这个版本。
为什么调用了重载的方法
当你调用 cd1.equals(cd2)
时,cd1
和 cd2
的静态类型是 CD
,编译器会选择与 CD
类型最匹配的方法签名。如果存在一个 equals(CD obj)
方法,编译器会选择这个重载方法。
结论
- 当使用重载方法时,编译器会选择最具体匹配的方法签名。因此,在你定义了
equals(CD obj)
方法并调用cd1.equals(cd2)
时,编译器会选择这个重载的方法。 - 为了确保所有情况下都能正确比较对象(尤其是在集合类中使用时),你需要重写
Object
类的equals
方法,签名为public boolean equals(Object obj)
。