动态绑定和多态
动态绑定是指“在执行期间(而非编译期)”半段所引用对象的实际类型,根据其实际的类型调用其相应的方法
如果用dos命令行中编译和执行java文件,具体过程是这个样的
当我对一个叫做HelloWorld的java文件编写完程序后(暂且认为是简单的打印HelloWorld),在命令行中的正确目录(指的就是存放该java文件的目录)下使用javac命令,这时会生成一个HelloWorld.class 文件,这个过程也就是编译过程,此时再通过输入java命令,这时就可以正确打印出HelloWorld!这个过程称为执行过程
我们用具体程序来分析一下什么叫做动态绑定:
class NewAnimal{
private String name;
NewAnimal(String name){
this.name = name;
}
public void enjoy() {
System.out.println("叫声。。。。。");
}
}
class NewCat extends NewAnimal{
private String eyesColor;
NewCat(String n , String c){
super(n);
eyesColor = c;
}
public void enjoy() {
System.out.println("猫叫声。。。。。");
}
}
class Lady{
private String name;
private NewAnimal pet;
Lady(String name , NewAnimal pet){
this.name = name;
this.pet = pet;
}
public void myPetEnjoy() {
pet.enjoy();
}
}
public class TestPolymoph {
public static void main(String[] args) {
NewCat c = new NewCat("catname" , "blue");
Lady l1 = new Lady("l1" , c);
l1.myPetEnjoy();
}
}
程序整体不难,建议自行阅读后再看分析
有三个类,分别是Animal,Cat,Lady,在Animal类中,有一个name的构造方法,还有一个enjoy的方法,模拟的是Animal的叫,子类Cat中,同样有一个name和eyesColor的构造方法,并且还重写了emjoy方法,有一个单独的Lady类,定义了一个Animal变量,有着自己的构造方法,而且还在自己的方法中调用了Animal的enjoy方法
现在进行一波内存分析
我们先不考虑下边的code seg,在观察一下上边的,这里的内存分析之前已经讲过很多次了,就不在赘述了。我们着重看一下code seg中的方法,这里将用到重要的动态绑定
现在来看我们有两个enjoy方法,分别是Animal.enjoy和Cat.emjoy,这时出现了一个问题,当我在调用enjoy这个方法的时候,到底调用的是哪一个?
如果我们单纯用 引用 的眼光看,那就很简单,pet调用的就是Animal.enjoy,但真的是这样嘛?实际上,运行后在内存中分配的Cat是根据类型来判定enjoy方法调用的哪一个,也就是
实际当中new出来的类型就是调用的方法
如果更深层的理解一下
在Animal类中有一个指针,它的作用是指向正确的enjoy方法,再运行这条程序后
public void myPetEnjoy() {
pet.enjoy();
}
它就从指向Animal的方法换成指向Cat.enjoy方法,在这个过程中突出了一个词动态
也就是说只有在运行期间,大白话就是在动起来才能知道究竟调用的是哪个方法,实际地址才会绑定调用方法中的地址
如果我们new一只Dog出来呢?
只需要新建一个Dog的类,而在Lady类和Animal类中并不需要做出修改,这里把整体程序的可扩展性推到了极致,这也就是面向对象核心中的核心
本文的最后简单总结一下多态,多态的使用有三个必要条件,它们分别是:
1.要有继承
2.要有重写
3.父类引用指向子类对象