注意一句话:任何子类对象都是父类对象这句话是正确的
(任何子类都可以看作父类)
首先看这个例题的完整代码:
package jiCheng_duoTai;
public class DuoTaiLiJieLianXiTi {
public static void main(String[] args) {
AAA a1 = new AAA();
AAA a2 = new BBB();
BBB b = new BBB();
C c = new C();
D d = new D();
System.out.println(a1.show(b));
System.out.println(a1.show(c));
System.out.println(a1.show(d));
// System.out.println(a2.show(b));
// System.out.println(a2.show(c));
// System.out.println(a2.show(d));
// System.out.println(b.show(b));
// System.out.println(b.show(c));
// System.out.println(b.show(d));
}
}
//先在本类的方法里面找,若没有再找父类(参数相同),如果还没有找到,就再找本类(参数的父类),如果还没有再去父类找
//1. this.m(o);2. super.m(o);3.this.m(super(o));4. super.m(super(O))
class AAA{
public String show(D obj) {
return ("A and D");
}
public String show(AAA obj) {//obj=b;
return ("A and A");
}
}
class BBB extends AAA {
public String show(BBB obj) {
return ("B and B");
}
public String show(AAA obj) {
return ("B and A");
}
}
class C extends BBB {
}
class D extends BBB {
}
现在来逐步分解,看每个过程的变化状态
状态一:
package jiCheng_duoTai;
public class DuoTaiLiJieLianXiTi {
public static void main(String[] args) {
AAA a1 = new AAA();
AAA a2 = new BBB();
BBB b = new BBB();
C c = new C();
D d = new D();
System.out.println(a1.show(b));
System.out.println(a1.show(c));
System.out.println(a1.show(d));
}
}
class AAA{
public String show(D obj) {
return ("A and D");
}
public String show(AAA obj) {//obj=b;
return ("A and A");
}
}
class BBB extends AAA {
public String show(BBB obj) {
return ("B and B");
}
public String show(AAA obj) {
return ("B and A");
}
}
class C extends BBB {
}
class D extends BBB {
}
结果显示:
答案分析:
a1是父类AAA的对象,b是子类BBB的对象,当b传到方法show中,先找有没有与b同参数的show方法,显然是没有的,因为a1这就是一个父类,所以找有没有与父类创建的参数,很显然是有的,所以就调用show(AAA obj)这个方法。
同理,对传来的参数c的时候,也调用show(AAA obj)这个方法。
对于传来的参数d的时候,在本类中就找到了同参的对象,所以就调用show(D obj)这个方法。
状态二:
public class DuoTaiLiJieLianXiTi {
public static void main(String[] args) {
AAA a1 = new AAA();
AAA a2 = new BBB();
BBB b = new BBB();
C c = new C();
D d = new D();
System.out.println(a2.show(b));
System.out.println(a2.show(c));
System.out.println(a2.show(d));
}
}
class AAA{
public String show(D obj) {
return ("A and D");
}
public String show(AAA obj) {//obj=b;
return ("A and A");
}
}
class BBB extends AAA {
public String show(BBB obj) {
return ("B and B");
}
public String show(AAA obj) {
return ("B and A");
}
}
class C extends BBB {
}
class D extends BBB {
}
结果显示:
答案分析:
注意:a2不是BBB子类对象,a2是AAA父类对象,真正运行的时候,new出来的是一个子类对象。
当传来参数是b的时候,首先在本类(BBB)中找有没有方法名和参数一样的方法,很显然有一个这样的方法show(BBB obj),这种想法是没有问题的,但是BBB子类继承父类AAA,当子类重写父类中的成员方法的时候,必须重写的是父类中存在的方法,子类中独有的方法不能在此情况下编译,因为编译的时候,要保证父类中含有这个方法(多态体现的就是父类中有的方法子类也有的这种方法才能够使用,父类中没有的方法在子类中是不能够使用的,不过可以将a2进行强制类型转换,BBB b = (BBB)a2;再用b.show(b)即可。)所以,因为a2是父类对象,父类中没有show(BBB obj)这个方法,这是BBB类自己的方法,所以a2.show(b)一定不会调用show(BBB obj)这个方法,当把b传来的时候,相当于调用父类中的show(AAA obj)方法,但是这个方法在BBB类中已经被子类所重写了,所以调用 的一定是那个重写的方法,即BBB类中的show(AAA obj)方法。
同理,当传来参数c的时候,也是调用BBB类中的show(AAA obj)方法。因为在子类BBB中没有同参数的方法,所以去父类中寻找,仍没有同参数的方法,所以就调用父类中的show(AAA obj)方法(父类引用指向子类对象)。 因为这个方法被子类BBB所重写,所以调用BBB类中的show(AAA obj)方法。
当传来参数d的时候,先在本类中寻找,发现没有同参数的方法,再去父类中寻找,发现了同参数的方法show(D obj),所以就调用这个方法。
状态三:
public class DuoTaiLiJieLianXiTi {
public static void main(String[] args) {
AAA a1 = new AAA();
AAA a2 = new BBB();
BBB b = new BBB();
C c = new C();
D d = new D();
System.out.println(b.show(b));
System.out.println(b.show(c));
System.out.println(b.show(d));
}
}
class AAA{
public String show(D obj) {
return ("A and D");
}
public String show(AAA obj) {//obj=b;
return ("A and A");
}
}
class BBB extends AAA {
public String show(BBB obj) {
return ("B and B");
}
public String show(AAA obj) {
return ("B and A");
}
}
class C extends BBB {
}
class D extends BBB {
}
结果显示:
结果分析:
注意:b是BBB类自己的对象
当传来参数b的时候,因为BBB类中存在同参数同方法名的方法show(BBB obj),所以直接就调用该方法。
当传来参数c的时候,首先按照思路,先在本类BBB中寻找是否有同方法名同一个类的参数的方法,显然是没有的,所以再去父类中寻找,在AAA类中寻找是否有同方法名同一个类的参数的方法,显然仍是没有的,所以再返回到本类中(BBB类)找这个参数是这个传来的参数的父类的,很显然,BBB类中的两个方法都是参数c的类的父类(c既是BBB子类的直接子类又是AAA的间接子类),所以都能够使用,那么就按照就近原则(这里所说的就近原则不是show(AAA obj)、show(BBB obj)写的先后问题,而是当子类有多个父类的时候,子类使用前一个父类),所以就调用BBB类中的show(BBB obj)方法。
当把d作为参数传来的时候先在本类中寻找没找到再去父类中找,找到后就调用该方法即可。
方法总结:
①先在本类中寻找有没有同参数同方法名的方法
②如果没有再去父类中寻找有没有同参数同方法名的方法
③如果没有就再在本类中寻找有没有参数是这个传来的参数的父类的
④如果还没有就再去父类中寻找有没有参数是这个传来的参数的父类的
补充:
package jiCheng_duoTai;
public class DuoTaiLiJieLianXiTi {
public static void main(String[] args) {
AAA a1 = new AAA();
AAA a2 = new BBB();
BBB b = new BBB();
C c = new C();
D d = new D();
System.out.println(a1.show(b));
System.out.println(a1.show(c));
System.out.println(a1.show(d));
}
}
class AAA {
public String show(D obj) {
return ("A and D");
}
public String show(AAA obj) {// obj=b;
return ("A and A");
}
public String show(BBB obj) {// obj=b;
return ("B and B");
}
}
class BBB extends AAA {
public String show(BBB obj) {
return ("B and B");
}
public String show(AAA obj) {
return ("B and A");
}
}
class C extends AAA {
}
class D extends BBB {
}
结果分析:
B是AAA的直接子类
C是AAA的直接子类
D是BBB的直接子类
对于a1.show(b)的调用,先找本类AAA类中是否有b的父类BBB的方法,我们发现是可以找到的,那么直接调用AAA类中的show(BBB obj)方法。
对于a1.show(c )的调用,先找本类AAA类中是否有c的父类C的方法,我们发现是没有的,那么就再去父类中寻找有没有C类的方法,因为AAA没有父类,所以这一步不做,再做下一步再在本类中寻找有没有参数是C类的的父类的,因为C类的直接父类是AAA,所以找到了就调用show(AAA obj)方法。
对于a1.show(d)的调用,先找本类AAA类中是否有d的父类D的方法,我们发现是有的,那么直接调用AAA类中的show(D obj)方法。
对于上面,如果我们修改一些代码:
class C extends BBB{
}
我们让C类的直接子类是BBB,而BBB的直接子类是AAA,那么C类就是AAA的简洁明了子类,那么再去System.out.println(a1.show(c ));会有什么不同呢?
我们发现结果由A and A变成了B and B,分析方法和上面一样,只是对于C类有多个类的时候先找直接父类BBB,直接父类没有的时候再去看间接父类AAA。