【转载】JAVA:动态绑定 和 静态绑定

通过虚拟机再看Java的静态绑定和动态绑定

 

动态绑定(auto binding):也叫后期绑定,在运行时,虚拟机根据具体对象的类型进行绑定,或者说是只有对象在虚拟机中创建了之后,才能确定方法属于哪一个对象。

不知道朋友有没有和我一样的疑问,动态绑定的意义是什么呢?

相信大家都知道,java的三大特性:封装,继承和多态,动态绑定就和多态有关。

由于继承和重写的存在,当方法中的类型为父类的时候,编译的时候不太好判断,方法到底要和哪个类绑定,也就是调用的方法依赖于隐式参数的实际类型。

这么说可能比较难理解,上代码,首先创建一个父类Animal,包含一个countLeg()方法。

 

再创建子类Dog,继承自Animal,重写countLeg()方法。

 

最后创建一个测试类,调用的方法传递父类Animal作为参数。

 

这个时候,对于countLeg()方法,是不是就不太好判断,animal到底该绑定哪个对象了!

既然我们在学习虚拟机,也学习了Class文件的知识,那我们就通过Class文件来一窥其妙。

首先,我们看一下Class文件里面的内容,笔者用的是IDEA,借助一下bytecode一下插件,看一下方法内的信息。

 

可以看到当前的引用类型还是指向Animal的,再来看一下方法中的指令,如下图所示。

 

1. aload:将指定的引用类型本地变量推送至栈顶。

这个好理解,那就是将animal推送至栈顶。

2. invokevirtual:用于调用对象的实例方法。

这个就是关键了,虚拟机会根据实际类型进行转换。

那么,转换的过程是什么样的呢?

当虚拟机创建Dog类的时候,会创建一个类的方法列表,同时包含父类的方法列表。

同时虚拟机会参数引用的实际地址,找到创建的这个Dog对象,查询方法列表,如果在Dog对象中找到这个方法,就直接调用。

如果没找到,就去查询父类方法,调用父类的方法。

静态绑定(static binding):也叫前期绑定,在程序执行前,该方法就能够确定所在的类,此时由编译器或其它连接程序实现。

那么什么样的方法调用是静态绑定呢?第一个,静态(static)方法是跑不了的,谜底就在谜面上啊,我的天啊,就是这么神奇!

 

还有一种让方法不被修改的方式,就是使用final进行修饰。

另外,使用private修饰的方法,默认就是final的的(现在已经很少使用final方法了)。

最后一个属于静态绑定的就是构造方法。

上一个小例子简单看一眼。

 

我们看一下编译之后的指令,test1()使用的是invokestatic指令,test3()使用的是invokespecial指令,test4()使用的是invokevirtual指令,老铁没毛病!

 

原文地址:http://baijiahao.baidu.com/s?id=1603249695758806932&wfr=spider&for=pc

posted @ 2019-06-18 15:42  lulusun  阅读(6046)  评论(0编辑  收藏  举报