Java基础第八章(多态)

多态

1.方法体现多态

方法重载体现多态

对象通过传入不同数量的参数,会调用不同的sun方法,体现出多态

方法重写体现多态

A类和B类是继承关系,通过不同对象调用对应类中重写的方法体现

2.对象体现多态

编译是javac,运行是java

(1)一个对象的编译类型和运行类型可以不一致

将父类的一个引用指向子类的一个对象(等号右边是新建对象,左边只是引用,使animal指向对象),animal的编译类型是Animal,运行类型是Dog。言外之意是父类的引用可以接收一个子类的对象

此时animal编译类型和运行类型一致,都是Animal

(2)编译类型在定义对象时就确定了,不能改变

上述例子中animal的编译类型就是Animal,不能再改变

(3)运行类型可以改变

(4)编译类型看等号的左边,运行类型看等号的右边

运行到调用cry方法时,看此时对象animal的运行类型是什么,此时运行类型是Dog,那么调用的就是Dog类中的cry方法;当animal的运行类型是Cat时,那么调用的就是Cat类中的cry方法

理解!

方法形参列表中是Animail animal,是父类的引用,可以接收子类的对象

多态的细节(向上转型)

多态的情况下,子类重写了父类的方法,对象调用该方法时,访问的是子类的重写方法,对象还可以调用父类中所有与子类不同名的方法(这种方法没有被重写)

1.向上转型

Animal是Cat的父类Object也是Cat的父类,两个都是向上转型

3.

父类的引用指向子类的对象,该对象可以调用父类所有的成员,不能调用子类特有的成员(注意是特有的,要是进行了方法的重写仍然可以调用子类的方法)

注意:以下只针对对象调用方法的例子,访问属性的规则和访问方法的不一样

在编译阶段(javac),由编译器来指定你能调用哪些成员(通过编译类型来查找能调用的成员),此时能调用的是编译类型所在类的成员,由编译类型来决定;运行阶段,由java来决定,此时,看你的运行类型。因此,在编译通过后,进入运行阶段,先在运行类型所在的类(子类)中查找是否有该方法,有且拥有访问权限就调用,没有就往上查找

//上述案例中,编译通过后,找到animal对象的运行类型,是Cat,因此在animal.eat()时先从Cat类查找是否有该方法;若找不到的话再向上查找,而且不能调用子类特有的方法

//在Cat类中找到eat()方法,因此最终调用的是Cat中的eat方法

向下转型

1.语法:子类类型 引用名 = (子类类型) 父类引用名,()不能少

  1. & 3.

父类的引用必须指向当前目标类型的对象,即:animal对象在创建时,Animal animal =new Cat(),这时指向的就是Cat类型的对象(运行类型是Cat),而将animal进行强制类型转换,得到的目标类型也必须为Cat,不能是与Cat类同级(都是Animal的子类)的引用;此步骤执行完,对象引用cat指向Cat对象,与animal指向一样,cat的引用类型仍然是Cat,编译类型是Cat,因此该对象可以调用子类Cat的成员。此方法与创建一个新的对象不一样,没有在栈中开辟一个新的空间。

属性重写

属性的访问规则

对象访问属性时只与对象的编译类型有关,编译类型是什么,就访问该类型类中的属性,base对象访问count,得到的值是10

sub.count得到的值是20

instanceof比较操作符

判断对象的xx类型(对象的运行类型)是不是xx类型或是不是xx类型的子类,返回一个布尔值

多态的练习1

Object object =“Hello”

第一句向上转型完整表达是 Object obj = new String("Hello");

第二句将obj强制转换成String类型,根据上面第一句,可以知道obj的运行类型是String类型,因此将一个String的引用指向obj指向一个运行类型也为String类型的即为向下转型

多态的练习2

创建类Sub的对象s,s的编译类型为Sub,运行类型为Sub。s.count访问属性,看编译类型,编译类型为Sub,访问Sub中的属性,结果是20。Base b = s相当于向上转型,将b指向s指向的地址空间,即指向原来创建的Sub对象。b == s,两个对象进行比较,比较的是地址,地址相同返回true。b.count看b的编译类型,为Base,因此返回10。最后一句b调用方法,看b的运行类型,为Sub,从Sub类中找该方法,返回20。

动态绑定机制

1.对象调用方法时(不仅仅只有对象.方法名(),还包括方法中调用其它方法,调用其它方法时也会和对象的运行类型绑定,先去对象的运行类型中查找有没有该方法),该方法会和对象的运行类型绑定

2.调用属性时,没有动态绑定机制,调用到类中的某个方法时,先在该类中寻找有无该对象的声明,有的话直接调用该对象的属性,不用根据对象的运行类型来查找

在上面案例,如果注销掉子类B中的sum()方法,a.sum()的过程为:根据对象a的运行类型为B,现在B类中寻找该方法,没找到向上查找父类A中的方法,找到父类中的sum()方法,方法体中为return getI()+10,此时又调用了一次getI()方法,根据动态运行机制,根据对象a的运行类型为B,又到B类中查找getI(),方法体中的内容是返回属性I,在B类中有属性I的声明,因此返回B类中的i,返回20,再回到原来的sum()中执行20+10,得到结果为30。

再注销掉sum1(),a.sum1()的过程为:根据对象a的运行类型为B,先去B类查找,找不到向上查找父类,找到父类A中的sum1(),执行i+10,在父类A中先查找有无局部变量i,没有,就找到父类A中的属性i(在A类中声明就返回A类的i),执行10+10,得到结果20

结果如下

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值