方法分派

本文详细解释了Java中的静态分派与动态分派的概念,包括静态类型与实际类型的区分,以及静态分派与动态分派的区别与应用场景。通过代码示例,展示了静态分派与动态分派的实现过程,并强调了它们在Java程序中的重要性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

可以从两方面划分:
静态分派及动态分派
单分派及多分派

静态分派及动态分派
静态分派:
先来看一段代码:
public class StaticDispatch {
    public void sayHello(Human guy) {
        System.out.println("hello, guy!");
    }
    public void sayHello(Man guy) {
        System.out.println("hello, man!");
    }
    public void sayHello(Women guy) {
        System.out.println("hello, women!");
    }
    public static void main(String[] args) {
        Human man = new Man();
        Human women = new Women();
        StaticDispatch sd = new StaticDispatch();
        sd.sayHello(man);
        sd.sayHello(women);
    }
}
class Human {}
class Man extends Human {}
class Women extends Human {}
输出:
hello, guy!
hello, guy!
上面代码如果把
    public void sayHello(Human guy) {
        System.out.println("hello, guy!");
    }
注释掉,则编译报错,这时需要用
sd.sayHello((Man)man);
sd.sayHello((Women)women);
才可通过编译,说明了man和women在编译时是Human类型的,虚拟机不会默认把父类变成子类(因为它不知道变成哪个子类),所以需要我们手动去强制转换。
我们把 Human称为变量的 静态类型 Man称为变量的 实际类型变量的静态类型和动态类型在程序中都可以发生变化,如下:
静态类型变化:
sd.sayHello((Man)man);
sd.sayHello((Women)women);
实际类型变化:
Human man = new Man();
man = new Women();
而区别是变量的静态类型是在编译阶段就可知的,但是动态类型要在运行期才可以确定,编译器在编译的时候并不知道变量的实际类型是什么现在回到代码中,由于方法的接受者已经确定是StaticDispatch的实例sd了,所以最终调用的是哪个重载版本也就取决于传入参数的类型了。实际上,虚拟机(应该说是编译器)在重载(注意:是重载overload,不是重写override)时是通过参数的静态类型来当判定依据的,而且静态类型在编译期就可知,所以编译器在编译阶段就可根据静态类型来判定究竟使用哪个重载版本。于是对于例子中的两个方法的调用都是以Human为参数的版本。
再看下面两段代码:
public class StaticDispatch {
    public void sayHello(Human guy) {
        System.out.println("hello, guy!");
    }
    public void sayHello(Man guy) {
        System.out.println("hello, man!");
    }
    public void sayHello(Women guy) {
        System.out.println("hello, women!");
    }
    public static void main(String[] args) {
        Man man = new Man();
        Women women = new Women();
        StaticDispatch sd = new StaticDispatch();
        sd.sayHello(man);
        sd.sayHello(women);
    }
}
class Human {}
class Man extends Human {}
class Women extends Human {}
输出:
hello, man!
hello, women!
public class StaticDispatch {
    public void sayHello(Human guy) {
        System.out.println("hello, guy!");
    }
    public static void main(String[] args) {
        Man man = new Man();
        Women women = new Women();
        StaticDispatch sd = new StaticDispatch();
        sd.sayHello(man);
        sd.sayHello(women);
    }
}
class Human {}
class Man extends Human {}
class Women extends Human {}
输出:
hello, guy!
hello, guy!
同样都是静态分派,只不过参数是子类型,这时,如果找不到与之匹配的子类型,可以往上找其父类型,依次类推。

动态分派:
先看下面代码:
public class DynamicDispatch {
    public static void main(String[] args) {
        Human man = new Man();
        Human women = new Women();
        man.sayHello();
        women.sayHello();
        man = new Women();
        man.sayHello();
    }
}
class Human {
    protected void sayHello(){
        System.out.println("hello Human!");
    };
}
class Man extends Human {
    @Override
    protected void sayHello() {
        System.out.println("hello man!");
    }
}
class Women extends Human {
    @Override
    protected void sayHello() {
        System.out.println("hello women!");
    }
}
输出:
hello man!
hello women!
hello women!

重写(override)方法的调用是根据实际类型来调用的!
总结:
重载(overload)方法的调用根据静态类型来决定,即采用静态分派!
重写(override)方法的调用根据实际类型来决定,即采用动态分派!

单分派和多分派
直至jdk6为止(jdk6以后不知道,因为《深入理解JVM》是基于jdk6来说明的),动态分派都是单分派,静态分派都是多分派,所以有以下两个名词:
静态多分派和动态单分派



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值