前言:
还在学习的过程中
水平有限,不足之处望请斧正。
1、多态的基本介绍
多态: 是指同一行为,具有多个不同表现形式。
- 多态是继封装、继承之后,面向对象的第三大特性。
- 程序中定义的引用变量所指向的具体类型和通过该引用变量发出的方法调用在编程时并不确定,而是在程序运行期间才确定
- 多态的前提
- 有继承/实现关系
- 有父类引用指向子类对象
- 有方法的重写 ( 不重写,无意义 )
- 使用父类型作为参数,可以接收所有子类对象,体现多态的扩展性与便利。
使用格式:
父类型 变量名 = new 子类/(接口)实现类 ;
变量名.方法名() ;
2、 多态的运行特点
调用成员变量时:编译看左边,运行看左边
调用成员方法时:编译看左边,运行看右边
编译看左边:iavac 编译代码的时候,会看左边的父类中有没有这个变量,如果有,编译成功,如果没有编译失败。
运行看右边:java 运行代码的时候,实际上运行的是子类中的方法。编译看左边: iavac 编译代码的时候,会看左边的父类中有没有这个方法,如果有,编译成功,如果没有编译失败。
运行看右边: java 运行代码的时候,实际上运行的是子类中的方法。
public class Test {
public static void main(String[] args) {
Father person = new Son();
//调用成员变量:编译看左边,运行也看左边
System.out.println("变量address的值为: " + person.address);
System.out.println("----------------");
///调用成员方法:编译看左边,运行看右边
person.eat();
//理解:
//Father person = new Son();
//现在用person去调用变量和方法
//而person是Father类型的,所以默认都会从Father这个类中去找
//成员变量:在子类的对象中,会把父类的成员变量也继承下的。父: address子: address
// 成员方法:如果子类对方法进行了重写,那么在虚方法表中是会把父类的方法进行覆盖的。
}
}
class Father {
String address = "中国";
public Father() {
}
public void eat() {
System.out.println("Father类运行了eat 方法");
}
}
class Son extends Father {
String address = "中国,上海";
public Son() {
}
@Override
public void eat() {
System.out.println("Son类运行了eat 方法");
}
}
运行结果:
变量address的值为: 中国
----------------
Son类运行了eat 方法
3、多态的优势和劣势
3.1、优势
- 多态形势下,右边对象可以解耦合,便于扩展和维护
Animal a = new Dog ();
a.eat ();
//如果此时让 cat 类进行运转,只需要将 Dog 换成 Cat 其他的无需改变
- 当父类型作为形式参数时,可以接收所有子类对象,有利于程序的扩展性
3.2、劣势
- 不能调用子类的特有功能
原因:
调用成员方法:编译看左边,运行看右边
在编译时会先检查左边父类中有没有这个方法,没有则直接报错,子类的特有功能在父类中是不可见的,故无法调用
解决办法:
将变量转换为子类类型( 转换时只能转换为原来定义时的类型,而不能转换为其它类型 )
转换的时候可以用 instanceof 关键字进行判断
Animal a = new Dog ();
if ( a instanceof Dog ){
Dog d = (Dog) a;
d.woof();
}else if ( a instanceof Cat ){
Cat c = (Cat) a ;
c.catchMouse() ;
}else{
System.out.println("没有这个类型可以转换");
}
//新特性
//先判断 a 是否为 Dog 类型,如果是,则强制转换为 Dog 类型 ,转换之后变量名为 d
//如果不是,则不进行转换,结果为 false
if ( a instanceof Dog d){
d.woof();
}else if ( a instanceof Cat c ){
c.catchMouse() ;
}else{
System.out.println("没有这个类型可以转换");
}
今天的分享就到这里了,期待与你共同进步!
如有不足欢迎留言指正 !