概念
我们都知道,在一个类或者父子类中,方法是可以同名的,而根据对象的类型,去选择方法具体的执行行为,就叫做分派;
分类
- 静态分派:静态分派发生在编译器,即根据对象的静态类型选择执行的方法
- 动态分派:动态分派发生在运行期,即根据对象的动态类型(实际类型)来选择执行的方法
这里就不得不说一下关于对象的类型:
对象的类型可以分为静态类型和动态类型(实际类型)
例如 :
Map<String, Object> map = new HashMap<>()
这里很明显运用了java的父类引用指向子类对象(向上转型),而Map就是这个对象的静态类型,HashMap则是这个对象的动态类型(运行期才实际去执行newInstance方法)
动态分派
首先创建一个父类
public class Pet {
/**
* 重写方法
*/
public void howl(){
System.out.println("宠物饿了");
}
}
再创建两个子类重写父类方法
public class Dog extends Pet{
@Override
public void howl() {
System.out.println("汪");
}
}
public class Cat extends Pet{
@Override
public void howl() {
System.out.println("喵");
}
}
利用多态实现动态分派
public class DynamicAssignment {
public static void main(String[] args) {
Pet dog = new Dog();
Pet cat = new Cat();
Pet pet = new Pet();
dog.howl();
cat.howl();
pet.howl();
}
}
这里可以看到控制台打印的结果
由此可见,同名方法在父子类重写中,执行的分派是动态分派,即根据对象的实际类型(动态类型)来决定执行的是哪个同名方法
静态分派
首先创建执行器
public class Executor {
public void howl(Pet pet){
System.out.println("宠物饿了");
}
public void howl(Dog dog){
System.out.println("汪");
}
public void howl(Cat cat){
System.out.println("喵");
}
}
演示静态分派
public class StaticAssignment {
public static void main(String[] args) {
Pet dog = new Dog();
Pet cat = new Cat();
Pet pet = new Pet();
Executor executor = new Executor();
executor.howl(dog);
executor.howl(cat);
executor.howl(pet);
}
}
这里可以看到控制台打印的结果
由此可见,同一个类中方法的重载,即一个对象在做为入参时去判断对象类型,实际是以这个对象的静态类型为判断依据
双分派
创建父类
public class Dog extends Pet{
/**
* 重写方法
*/
public void howl(Executor executor){
executor.howl(this);
}
}
创建子类
public class Cat extends Pet{
/**
* 重写方法
*/
public void howl(Executor executor){
executor.howl(this);
}
}
public class Dog extends Pet{
/**
* 重写方法
*/
public void howl(Executor executor){
executor.howl(this);
}
}
创建执行器
public class Executor {
public void howl(Pet pet){
System.out.println("宠物饿了");
}
public void howl(Dog dog){
System.out.println("汪");
}
public void howl(Cat cat){
System.out.println("喵");
}
}
测试双分派
public class DoubleAssignment {
public static void main(String[] args) {
Pet pet = new Pet();
Pet dog = new Cat();
Pet cat = new Dog();
Executor executor = new Executor();
pet.howl(executor);
dog.howl(executor);
cat.howl(executor);
}
}
控制台打印结果
这里其实执行了两次分派,第一次是
pet.howl(executor);
dog.howl(executor);
cat.howl(executor)
这里执行的是动态分派,即根据对象的动态类型选择执行的方法,根据之前的结论,此时动态分派到子类的实现方法中,以cat为例,则执行的是以下代码
executor.howl(cat);
此时传入的对象类型是实际类型,而不是父类类型,进行第二次分派(静态分派)则执行以下代码
public void howl(Cat cat){
System.out.println("喵");
}
故控制台打印结果"喵"