多态
封装:对象代表什么,就得封装对应的数据,并提供数据对应的行为。将零散的数据和行为封装成一个整体
继承:由于封装的东西越来越多,并且很多的属性和方法是重复的,代码复用性差,为了解决这个问题,于是乎有了继承
多态:指对象的多种形态。
用new关键字创建一个学生类的对象,并赋值给一个数据类型为学生类型的变量,那么我们可以认为,用new所创建的对象是目前是一个学生形态
同理,用new关键字再创建一个学生类的对象,并赋值给一个数据类型为Person类型的变量,那么我们可以认为,用new所创建的对象是目前是一个Person形态
这就是多态。应用场景:
教务、学生管理系统的注册,包含的范围有老师、管理员、学生,注册方法里的形参只能写一个,老师类或管理员类或学生类,而这个形参再确定之后是没法在程序运行时修改的,所以为了解决这样的问题,首先想到的就是重载方法,即根据每个形参的不同,选择对应的方法。但这样的方法是低效率的,应为类的种类比较多,要复写很多代码,而且在这个过程中如果要增加新的类成员,就要再添加代码,并且要进行一系列的调试操作,非常不可取。所以说,这时候多态就派上了用场。我们可以让类成员们的父类作为形参,不管有多少的类成员或是新增类成员,只要是继承于形参,那么都可以调用这个方法。那么这个时候就会觉得那直接不设置形参不就可以了,那么这就面临了一个新问题,你创建的对象需要调用专属方法,那你就还需要在方法内部在创建本类,再次调用,又增加了代码量,并且调用很受限制。所以,将父类作为形参还有非常重要的一点就是,只要子类进行了方法的重写,那么jvm会根据实参的类型来选择对应的方法来调用。
什么是多态:就是同种对象表现出的不同形态
表现形式:把子类的对象赋值给父类数据类型的变量
多态使用前提:
- 有继承/实现的关系
- 有父类引用指向子类对象(指的就是表象形式:Fu f = new Zi();)
- 有方法重写
总结:
什么是多态?
多态的前提?
多态的好处:
使用父类作为形参,可以接收所有子类的对象
体现多态的拓展性和便利
多态调用成员的特点
调用成员变量
口诀:编译看左边,运行也看左边
调用成员方法
口诀:编译看右边,运行也看右边
测试类中的代码:
运行结果:
分析:
多态的优势和弊端
优势
- 在多态状态下,右边对象可以实现解耦和,便于扩展和维护
创建一个父类状态下的子类,当需要修改对象时,只需要修改实例化的代码。往后所对应的变量、方法等代码会自动根据对象的专属性(继承了的变量、方法,对特有的变量、方法,无法调用)来调用相应的变量、方法 - 定义方法时,使用父类类型作为参数,可以接受所有子类对象,体现了多态的扩展性与便利
弊端
前面提到的专属性,主要是强调子类中的方法重写,但对于子类中特有的方法,父类类型的子类对象是无法调用的
解决方法:可当需要调用子类特有方法时,对象的类型进行强制转换,转换为子类类型,如,Person p = new Student();强制转换:Student s = (Student)p;
注意:转换时,只能是当前父类类型的子类对象转化为当时创建时的实例化子类,不能是其他子类,如,Teacher t = (Student)p;这样就报错
但同时会出现这样一个问题,就是不清楚创建的这个父类类型的子类对象是哪一个子类实例化的,所以在进行强制转换之前我们可以进行一个判断,比如:
if(d 是 子类Dog类实例化的){就强制转化为Dog类型}
else if(d 是 子类Cat类实例化的){就强制转化为Cat类型}
else{......}
实现语句:
instanceof关键字
if(a instanceof Dog);句意为,判断对象a,是不是利用Dog类进行的实例化(换句话说,就是判断对象a记录的是不是Dog类型),是为ture,不是为false
在进行完类型判断之后,根据结果来判断是否进行强转,语句如下:
if(a instanceof Dog){
Dog d = (Dog)a;
d.特有方法();
}
jdk新特性:将对象的实例化类型判断与强制转换和成一条语句,如下:
if(a instanceof Dog d){
d.特有方法();
}
句意为,当Dog为a的实例化子类时,就将a转化为Dog类型对象,对象名为d
面试问题:多态进行方法调用时会出现什么问题?
回答:首先是不能够调用子类当中特有的方法。如果需要调用,就必须进行对对象类型的强制转换。转换过程中会出现转换类型不一致的问题,我们可以通过instanceof关键字类解决,进而将对象转化为真正的子类类型,从而调用子类独有的功能