码迷,mamicode.com
首页 > 其他好文 > 详细

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

时间:2016-06-14 10:20:15      阅读:160      评论:0      收藏:0      [点我收藏+]

标签:

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

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



静态分派

首先我们来看一段源码:

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!


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

标签:

原文地址:http://blog.csdn.net/u014629433/article/details/51668543

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!