Java继承与方法调用疑问:为何ab.show(b)输出B and A而非B and B
为什么代码运行结果是"B and A"而不是"B and B"?
这其实是Java中**方法重载(Overload)和方法重写(Override)**的区别,再加上编译时静态类型与运行时动态类型的判断逻辑导致的,我给你拆解一下:
先理清两个核心逻辑
- 编译时类型:就是变量声明时的类型(比如
A ab = new B();里的ab,编译时类型是A),编译器只会根据这个类型来查找可用的方法。 - 方法重载看编译,方法重写看运行:重载是编译阶段就确定好要调用哪个方法签名;重写则是编译确定签名后,运行时根据对象实际类型执行对应实现。
一步步分析你的代码
- 先看变量定义:
A ab = new B(); // ab的编译时类型是A,实际运行时指向的是B对象 B b = new B(); // b的编译时和运行时类型都是B - 调用
ab.show(b)时,编译器先做第一步匹配:- 编译器只认
ab的编译时类型A,去A类里找匹配的show方法,A里只有show(D obj)和show(A obj)两个选项。 - 传入的参数
b编译时类型是B,而B是A的子类,所以编译器会把b向上转型为A,最终匹配到show(A obj)这个方法签名——这一步是编译时就敲定的,完全不会考虑B类里新增的show(B obj),因为A类里根本没有这个方法。
- 编译器只认
- 到了运行阶段:
因为ab实际指向的是B对象,而B类重写了show(A obj)方法(你加的@Override注解也能佐证这一点),所以最终执行的是B类里的这个重写方法,返回结果自然是"B and A"。
为什么不会触发B.show(B obj)?
B.show(B obj)是B类新增的重载方法,不是对父类方法的重写。编译器在处理ab.show(b)的时候,根本不知道ab实际是B对象,它只能基于ab的编译时类型A来查找方法,而A里没有接受B类型参数的show方法,所以这个重载方法从一开始就不在编译器的候选列表里。
如果想让它输出"B and B",只需要把ab的编译时类型改成B就行:
B ab = new B(); B b = new B(); System.out.println(ab.show(b)); // 此时就会调用B.show(B obj),输出"B and B"
内容的提问来源于stack exchange,提问作者Borden Alex
相关产品推荐
相关产品推荐

