Java中向上转型对象为何调用父类方法实现?——同名不同签名方法的调用困惑
为什么向上转型后调用的是父类的方法?
嘿,这个问题其实戳中了Java里方法重载和动态绑定的核心区别,我来给你拆解明白:
首先,先明确两个关键概念:
- 方法重写(Override):子类必须定义和父类完全相同的方法签名(方法名、参数类型/数量/顺序都一致,返回值也要兼容),这样运行时才会触发动态绑定,调用子类的实现。
- 方法重载(Overload):方法名相同但参数列表不同,这是完全独立的两个方法,和重写没有关系。
回到你的代码:
class A{ public void fun(double d){ System.out.println("A"); } } public class C extends A{ public static void main(String[] args){ A x = new C(); x.fun(6); //prints "A" } public void fun(int i){ System.out.println("C"); } }
问题出在这两步:
编译阶段:编译器只看引用类型
你声明的x是A类型的引用,所以编译器会在A类(包括它的父类)里找能匹配fun(6)的方法。6是int类型,A类里没有fun(int),但Java支持基本类型的自动转换——int可以自动转成double,所以编译器匹配到了A类的fun(double)方法。这一步就已经确定了要调用的方法签名是fun(double),完全没考虑子类C里的fun(int),因为A类里根本没有这个方法,编译器看不到子类的这个重载方法。运行阶段:动态绑定只针对重写的方法
动态绑定(也就是运行时决定调用哪个类的方法)只在方法被重写的时候生效。但你的子类C的fun(int)和父类A的fun(double)是两个完全不同的方法(方法签名不一样),不属于重写。所以运行时就直接执行编译阶段确定的A类的fun(double)方法,自然输出"A"。
验证一下:如果改成重写会怎样?
要是你把子类的方法改成重写父类的fun(double):
public class C extends A{ public static void main(String[] args){ A x = new C(); x.fun(6); //这时候会打印"C" } // 重写父类的fun(double) @Override public void fun(double d){ System.out.println("C"); } }
这时候因为方法签名完全一致,属于重写,运行时动态绑定就会生效,调用子类的实现,输出"C"。
总结一下:向上转型后,编译器只认引用类型的方法列表,只有当方法被重写时,运行时才会切换到子类的实现;重载的方法因为签名不同,编译器根本不会考虑子类里的同名不同参方法~
内容的提问来源于stack exchange,提问作者Kay.Z
相关产品推荐
相关产品推荐

