嗨,你好,
下面我们一起来学习多态和虚方法调用。
所谓多态呢是指在一个程序当中 相同的名字表示不同含义,
或者我们说呢你就写一个东西,但是它实际,根据实际情况
来表达它不同的含义,来进行不同的调用。那么多态有两种情形,
一种是编译时的多态,编译的时候就能决定的,这种呢最常见的一种形式就是
overload,就是重载,那多个同名的方法,比如说我们有person,人,他有一- 个sayHello,
那如果调0个参数呢,它会知道调这个函数,同样 的sayHello如果是你带一个参数,它也知道调另一个方法。
所以这种呢就是编译的时候就能够,同样的名字 表示它能自动来决定不同的方法调用,
这是编译时的。还有一种呢,更重要的就是运行时候的多态。
也就是说我们写同样的方法,系统来决定它应该调哪个方法。
比如说最典型的就是覆盖,override,就override呢,
这种子类对父类的方法进行覆盖, 同样的名字,由于它进行了覆盖,
那么系统呢它会进行自动地来决定调哪个方法,那么它是通过什么方法决定呢?
就是所谓的动态绑定,在其他语言里面叫动态 绑定,Java也有类似的那个概念。也就是说
它来动态地决定我们这个对象,实际对象来决定 它调子类的呢还是父类的同名方法。
那这个也称为虚方法调用,因为这个方法呢在我们在写的时候呢系统
它实际上是调这个方法呢,它真正调的方法呢,它认为是虚的,真正的方法,
它在运行时候再去决定,所以它也称为虚方法调用。所以呢
这种自动的确定调用子类对象的方法,我们就称为 覆盖式的这种多态,也称为运行
时多态。那么多态是面向对象语言的一个重要的特点, 我们说封装、继承和多态,那这
节其实讲的就是多态,它是 面向对象的一个重要特性,它能够大大的提高程序
的抽象程度和简洁性,然后它也可以呢, 使我们写程序呢更方便,不然我们会
要实际地去决定它是那个对象,然后这个程序写起来那就很麻烦了。
那在这里面我们涉及到子类和父类的对象的问题呢,我们有一个
上溯造型的这样,upcasting,这样一个概念。
也就是说把可以把派生那个类型当成基本类型来处理。
那个派生类型,比如说我们这个典型的person p等于new
student 这个person的引用呢,它可以引用到一个student对象上面,因为
student是person的一个子类,所以这种引用呢就称为上溯造型。
我们再举个例子,比如说我们调用一个函数,它需要一个person做参数, 那我们可以给它传一个new
person,还可以传一个呢 new student,也就是说只要它是子类的或者是同一类型,
或者是子类都可以传进来,这种就称为上溯造型。
那么上溯造型就决定另一个问题了,就我们传进去的参数, 既然是实际类型了和我们写的类型不一样了,
那么它在运行的时候呢来调用哪个呢,就是用虚方法来调用,虚方法调用呢,
就实现运行多态,也就是说子类如果重载了父类的方法,在运行时候
它会根据该方法的实际的类型,实际的实例,我们
传进去的是一个student对象,那么它就会根据student这个对象来决定哪个方- 法调用。
所以它会自动的,根据实际的, 而不是它声明的person,这种呢就是称为呢
叫做动态绑定,就是所有的,
几乎所有的,我们后面会讲到哪些不会动态绑定。Java里面它特别好,
就是说我们不做特殊声明,它自动的就是动态绑定。
这是一般的进行,不像我们有的语言可能还要进行特殊的声明,我们这里不需要。
让我们看一个例子, 比如说我们有一个doStuff,它需要带一个Shape
形状对象,这个形状对象呢我们调用形状对象的draw函数, 画函数,但是我们这里呢有三种
形状对象的子类,比如说circle对象,然后 就是三角形还有line对象,
然后在这里面呢我们do iii这个stuff,那么它的结果是怎么样的呢?我们看看这个例子。
好,我们实际看一下这个例子,这个例子里面呢
有形状这个类,然后它有个做方法,
然后circle、triangle等等,那么它都继承了 这个形状对象,同时呢
override做方法,也就是说具体的这个circle或者 triangle三角形,那么它的画的方法是不一样的,
那我们这里面有一个函数呢,它是要用,声明了一个
它这里声明了用一个形状对象做参数,然后我们实际在调用的时候,我们分别传进了
这三个不同的这个子对象,子类对象的实例,
传进去,然后这个实例呢,它在做的时候呢,画图的方法的时候呢, 它会画什么样子的呢?它会按,它会
用这个形状的画方法来画吗? 那当然不合理了,因为我们知道,你既然传进去的是一个三角形,那你就应该
按三角形的方法来画,所以这是比较合理,也就是这种 方法,我们运行一下看看效果。
你看在这里面呢,确确实实虽然我们从形式上
看这是形状,但是我们实际传进去的是圆,那它就画圆,
如果是画三角形,它就画三条直线等等,所以这种是比较合理
的,所以这种也是Java里面自动的,自动的情形。
那这个就称为虚方法的调用,简单的说呢就是它会自动的根据实例来决定调哪个方法。
这个就是虚方法调用。当然这里又带来另一个细节的问题,就是说如果我们既然可以传进去它
对象的这种实例,对象的 子类的这个实例,所以我们有的时候需要的动态类型
判断它究竟是什么,Java里面有一个运算符叫instanceof,
就判断它是不是某个变量,是不是某个类型,当然这个类型包括,
就是说它的,如果它是这种实际就是这种类型,它会true,
返回一个true,如果它是它的子类型,它也会返回一个true,那因为它表示它是否
是它的子类型,所以我们就可以通过这个运算符来进行判断。
我们看一个例子。请看这里一个例子,那这里面呢 我们是有object的对象,它是所有类的子类了,
所以这个数组呢它里面每一个元素可以附 它的子类,比如说整数啊,这个整数是一个对象,
还有一个字符串等等,那我们附了这些 不同的对象,我们在实际用的时候我们就可以判断这个对象
instanceof,它是不是这个,如果是这个的话,我们可以强制类型转换,
然后呢调用它,它一些方法,所以也就是用instanceof 可以对实际的那个对象类型进行判断。