方法分派——了解虚拟机是怎么执行重载和重写的方法

首先看一个例子:


public class TestDemo{
	
	static abstract class Human{	
	}
	
	static class Man extends Human{
	}
	
	static class Woman extends Human{	
	}
	
	public static void sayHello(Human guy) {
		System.out.println("hello guy");
	}
	
	public static void sayHello(Man guy) {
		System.out.println("hello man");
	}
	
	public static void sayHello(Woman guy) {
		System.out.println("hello waman");
	}
	public static void main(String args[]) {
		TestDemo testDemo=new TestDemo();
		Human man=new Man();
		Human woman=new Woman();
		testDemo.sayHello(man);
		testDemo.sayHello(woman);
	}
}

输出都是“hello guy”

那么有没有想过为什么会都会执行第一个方法呢?在这里虚拟机实际上是按照静态分派的方式来找到相应的方法的。

首先我们要知道一些概念:Human为变量静态类型,也叫外观类型。Man和Womn叫做实际类型

虚拟机在重载过程中是通过参数的静态类型而不是实际类型来作为判定的依据的

所有依赖静态类型的分派而确定执行版本的叫做静态分派。静态分派的发生是在编译阶段,因为在编译阶段静态类型已经被确定了。

静态分派典型的应用就是方法重载。

下面再来看一个例子:



import java.io.Serializable;

public class TestDemo{
	
	public static void sayHello(int a) {
		System.out.println(a);
	}
	
	public static void sayHello(long a) {
		System.out.println(a);
	}
	
	public static void sayHello(float a) {
		System.out.println(a);
	}
	
	public static void sayHello(double a) {
		System.out.println(a);
	}
	
	public static void sayHello(Character a) {
		System.out.println(a);
	}
	
	public static void sayHello(Serializable a) {
		System.out.println("hello serializable");
	}
	
	
	public static void main(String args[]) {
		sayHello('a');
	}
}

输出:'a'

如果把参数是Character 类型的sayHello方法注释掉,那么就会输出:97,显然是执行了sayHello(int a)

如果接着把参数是int 类型的sayHello方法注释掉,那么会执行sayHello(double a)

后面的大家可以自己试试。

为什么会这样执行呢?其实这也是静态分派的另一种情况——优先级执行。因为输入的是字符型,那么就会先执行参数为字符型的那个方法,如果没有参数为字符型的方法,那么接着会执行参数为int型的方法,因为字符a的十进制类型是97,执行的顺序为:

char->int->long->float->double。但是切记不可以转换到byte和short型,向下转型是不安全的。

那么,如果把所有的sayHello()方法都注释掉,只留下参数为Serializable这个sayHello方法,此时就会输出"serializable hello ",这是因为character实现了Serizable接口,如果该类中没有与之类型匹配的方法,那么就会执行与他接口类型匹配的方法。

下面讲解动态分派:

package com.demo.test;

public class TestDemo{
	static abstract class Human{
		protected abstract void sayHello();
	}
	
	static class Man extends Human{
		protected void sayHello() {
			System.out.println("man say hello");
		}
	}
	
	static class Woman extends Human{
		protected void sayHello() {
			System.out.println("woman say hello");
		}
	}
	
	public static void main(String args[]) {
		Human man=new Man();
		Human woman=new Woman();
		man.sayHello();
		woman.sayHello();
		man=new Woman();
		man.sayHello();
	}
}

输出:

man say hello
woman say hello
woman say hello

那么虚拟即是怎样找到要执行的方法的呢?这里显然不能再用静态类型来分析了。

要确定重写方法的执行,虚拟机有两条规则:

1,确定静态类型,在这里是确定是Human还是Man,Woman

2,去顶方法参数,第一步确定了是去父类还是子类找方法,为了放置类中出现重载,第二部用参数去顶方法。

通过这两步确定了虚拟机具体要执行那条方法,这也就是多分派。静态分派属于单分派。

发布了75 篇原创文章 · 获赞 31 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/yaoyaoyao_123/article/details/99203737