[jvm解析系列][十二]分派,重载和重写,查看字节码带你深入了解分派的过程。

重载和重写是分派中的两个重要体现,也是因为这个原因我们才把重载和重写写在了标题上。这一章我们的很多部分都在代码试验上。

总的来说分派分为静态分派动态分派两种。



静态分派

首先我们来看一段源码:

public class Dispatch {
	public static void main(String[] args){
		Animal a = new Dog();
		Animal b = new Cat();
		sound(a);
		sound(b);
	}
	public static void sound(Animal a){
		System.out.println("....");
	}
	public static void sound(Dog a){
		System.out.println("wang..");
	}
	public static void sound(Cat a){
		System.out.println("miao..");
	}
	static class Animal{
		
	}
	static class Dog extends Animal{
		
	}
	static class Cat extends Animal{
		
	}
}
这段源码就是写了三个重载的方法,根据参数的不同输出不同的信息。应该大家都能知道正确输出,输出如下:

....
....
Animal  a = new Dog();在这个里面我们把Animal叫做外观类型(静态类型)把Dog叫做实际类型。静态类型是在编译期可知的,但是一个对象的实际类型要在运行期才可知。而jvm在重载的时候通过参数的静态类型作为判定依据。我们来看一下字节码是不是和我们想的一样


看到图中invokestatic的字符引用,我们应该就知道了编译时期确实完成了方法的定位。

而这些需要靠静态类型定位方法的情形称为静态分派,静态分派发生在编译阶段。也就是说在这个方法执行之前仅仅在编译阶段,sound方法就认定了最后要输出一个"...."而不是wang和miao。





动态分派

我们依然先给一段代码:

public class Dispatch {
	public static void main(String[] args){
		Animal a = new Dog();
		Animal b = new Cat();
		a.sound();
		b.sound();
	}
	static class Animal{
		public void sound(){
			System.out.println("......");
		}
	}
	static class Dog extends Animal{
		public void sound(){
			System.out.println("wang!");
		}
	}
	static class Cat extends Animal{
		public void sound(){
			System.out.println("miao!");
		}
	}
}
这一段代码的输出结果相信我不用贴大家都明白。
wang!
miao!
但是,为什么jvm能够找到这一段方法并且执行的呢?

我们来看一下javap的输出信息


图中画红线的两个部分就是编译后的字节码文件了,他们调用的依然是animal的sound方法,看来动态分派不是在编译期完成的。问题就出在了invokevirtual上面了

jvm运行invokevirtual方法有一个过程,大致如下。

1、找到操作数栈顶的第一个元素所指向的对象的实际类型,记作C。

2、如果C与常量中的描述符和简单名称都符合的方法,说明这个方法就是我们找的,只需要进行访问权限校验(看看是不是private之类)。

3、如果不符合描述符或简单名称。则对C的父类进行第二步中的搜索。

4、最终都没有找到抛出AbstractMethodError。

可能第3步比较难懂,我们再来仔细说明一下

如果我们把代码修改如下:

public class Dispatch {
	public static void main(String[] args){
		Animal a = new Dog();
		Animal b = new Cat();
		a.sound();
		b.sound();
	}
	static class Animal{
		public void sound(){
			System.out.println("......");
		}
	}
	static class Dog extends Animal{
		public void sound(String a){//修改后的方法
			System.out.println("wang!");
		}
	}
	static class Cat extends Animal{
		public void sound(){
			System.out.println("miao!");
		}
	}
}
那么很明显上述中的C在Animal a = new Dog();中就是Dog类,Dog类中只有一个sound(string)的方法并不存在一个sound()方法,所以去C的父类中即Animal类中找到sound方法,最终输出如下:

......
miao!


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值