先上自己写的一个小示例:
/**[多态/动态绑定]
* Dynamic_binding.java
* @author 吕浪
* @My Email:784975698@qq.com
* @Created on 2016年7月30日
*/
package com;
class Dad
{
public void print()
{
System.out.println("I'am Dad");
}
}
class Son extends Dad
{
@Override
public void print()
{
System.out.println("I'am Son");
}
}
class Music //标准风格:类名首字母大写
{
public void print(Dad obj) //标准风格:成员方法则首字母小写
{
obj.print();
}
}
public class Dynamic_binding {
//一个java文件只能有一个public的类
public static void main(String[] args) {
// TODO Auto-generated method stub
//Son son = new Son();//若自己没定义构造函数系统会自动为我们建立一个默认构造函数
Dad son = new Son(); //这句效果等同于上面一句
Music music = new Music();
music.print(son);
}
}
/**
* 输出为:
* I'am Son
*
* 解析
* 1.面向对象语言三大基本特征:
* (1)封装(数据抽象成类,可隐藏类内部具体实现对外开放标准接口)
* (2)继承
* (3)多态
*
* 2.多态指继承出来的子类可以通过覆盖(Override)的方式使同一个方法可以具有其各自的特性
* 多态通常是通过动态绑定来达到目的的。
* 注意区别覆盖Override和重载Overload[重载是通过参数列表或返回值定义同名函数但不同功用的函数]
*
* 3.关于动态绑定的解释,引自《Java编程思想》:
* “将一个方法调用同一个方法主体关联起来被称作绑定。
* 若在程序执行前进行绑定(如果有的话,由编译器和连接程序实现),叫做前期绑定。
* C语言只有前期绑定。
* 而后期绑定或者叫动态绑定或运行时绑定则是在程序运行时根据对象的类型进行绑定。
* 编译器并不知道对象的类型,但是方法调用机制能找到正确的方法体,并加以调用。
* Java中除了static方法和final方法(private方法属于final方法)之外,其他所有的方法都是后期绑定。
* 这意味着通常情况下,我们不必判定是否应该进行后期绑定--它会自动发生。”
*/
这里看到别人写的一个博客用到了反编译这种高大上的方法验证动态绑定与否感觉挺好的:
其实吧,按我目前的理解的话,是这样的,我们知道,代码区跟变量(对象)区是处在内存中不同的区域中的,对象A调用方法f(),如果f()只有一个没被重写,那么就不存在说编译器看到了两个一模一样的函数不知该选谁的问题,所以编译时绑定,但如果类Father和类Son同时都有函数f(),也就是Son重写(Override)了f()方法,那么编译器该挑哪一个出来呢?其实自己也会去想,代码不是写明了new的是Son对象吗,怎么编译器不会看得出来我要调的是Son里面的f()方法啊。我猜(是啊,目前只能用低级别的猜)是因为编译器没那么智能没那么强大或者说不想去花费额外太多的资源去干那样的事……还是用形象点的方式说一下个人的理解吧:类Father有跟线跟它自己的f()方法相连,然后Son类也有跟线跟自己的f()方法相连,同时Father跟Son之间也有跟线是相连的,并且因为Son继承自Father,所以在编程语言的理论上跨过一根线就能够从村口(因为Son也是一个(is a)Father,所以不说从Son出发,姑且说从村口吧)出发找到Father的f()方法,那么问题来了,现在你要编译器挑f()方法,两边都能跨一条线就到达,那么该去哪一边呢?所以问题就来了。然后当运行时呢?前面如果已经new出了Son的空间,然后再去调用f()函数,那么如果Son空间里就有一个f()方法,那我直接取它的,如果Son空间里没有,那我去跟它相连的Father空间(Father空间会随着new Son()也被创建)中找f()方法出来去使用。
呃,好像这样说也是糊里糊涂的。等以后自己对于这块知识有了更深刻的理解再补充讲解下吧。