You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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");
    }
}

问题出在这两步:

  1. 编译阶段:编译器只看引用类型
    你声明的x是A类型的引用,所以编译器会在A类(包括它的父类)里找能匹配fun(6)的方法。6是int类型,A类里没有fun(int),但Java支持基本类型的自动转换——int可以自动转成double,所以编译器匹配到了A类的fun(double)方法。这一步就已经确定了要调用的方法签名是fun(double),完全没考虑子类C里的fun(int),因为A类里根本没有这个方法,编译器看不到子类的这个重载方法。

  2. 运行阶段:动态绑定只针对重写的方法
    动态绑定(也就是运行时决定调用哪个类的方法)只在方法被重写的时候生效。但你的子类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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.01 03:17:44