注意,方法重载时,方法返回值没有什么意义,方法签名是由方法名和参数列表决定的,返回类型不是签名的一部分!
// A 类
public class A {
public String show(D object) { return "A and D"; }
public String show(A object) { return "A and A"; }
}
// B 类
public class B extends A {
public String show(B object) { return "B and B"; }
@Override
public String show(A object) { return "B and A"; }
}
// C 类
public class C extends B{ }
// D 类
public class D extends B{ }
测试类:
public class Tester {
public static void main(String[] args) {
A a = new A();
A aRefB = new B();
B b = new B();
C c = new C();
D d = new D();
System.out.println("1-" + a.show(b));
System.out.println("2-" + a.show(c));
System.out.println("3-" + a.show(d));
System.out.println("4-" + aRefB.show(b));
System.out.println("5-" + aRefB.show(c));
System.out.println("6-" + aRefB.show(d));
System.out.println("7-" + b.show(b));
System.out.println("8-" + b.show(c));
System.out.println("9-" + b.show(d));
}
}
输出:
1-A and A
2-A and A
3-A and D
4-B and A
5-B and A
6-A and D
7-B and B
8-B and B
9-A and D
解析:
前三个比较容易,因为 B、C 都本质上是 A 类,所以 1 和 2 都进入了 A 类中签名为 show(A) 的方法。
但是第四个非常奇怪,A 对象类型引用了一个 B 类型的实例,输出是 B and A,而不是想象中的 B and B,为什么呢?
这里有一个新知识点:决定调用哪个方法的是引用变量类型。
两种理解:
- 理解一: (存疑)
拿这里的aRefB.show(b)
来说好了,aRefB
虽然是A
类型的引用,但首先会查找B
对象中的方法 (因为它实际的指向是B
类对象),而引用b
正好是一个B
类型 (实质上是is-a
A
类型)**,所以符合B
对象中签名为show(A)
的方法,就输出了B and A
。如果B
类型中没有符合签名的方法,那么会从父类中查找,继续这个过程直到找到或者报错。
- 理解二:(可信)
还是以aRefB.show(b)
来说,首先aRefB
指向(引用) 一个B
类型对象,假设是temp
,temp
有3个show()
方法,分别是来自父类A的两个:show(D)
,show(A)
,其中show(A)
被子类覆盖,相当于和子类的show(A)
合并。除了父类,自己还独有的一个show(B)
,然后有个aRefB
指向它,只不过,被强制转换成A
类型,那么,aRefB
可用的方法就被阉割了,阉掉了A类看不到的方法,也就是只剩下了A
类自己的方法:show(D)
,show(A)
,接下来,参数b
是一种A类型,所以是调用了A类的show(A)
方法,但是,在对象temp
执行时,show(A)
是B类的show(A)
,故,输出 4- B and A
-
沿用这一思想,看6- A and D:
aRefB
有3个方法可用,判断参数d
符合show(D)
,直接输出A and D; -
再看第九题,b有三个方法,
show(D)
一种,show(A)
和子类show(A)
看成一种,子类show(B)
一种,然后看参数d
,符合第一种show(D)
,故直接输出A and D, -
【注】 :那些”先子类查找,再父类啥的“,太繁琐,直接 扁平化理解,全能看见,然后划分出哪些是子类的,哪些是父类的,注意一下继承导致的覆盖即