多态(polymethod)
问题引入
多态是建立在封装和继承的基础之上的
为什么需要多态?
代码的复用性不高,不利于维护
举例
人给动物喂食这个方法,如果动物类别添加了,那食物类别也需要添加,那必然会造成需要不断地添加方法,就会造成代码的复用性不高
方法体现多态
(1)同类中方法的重载和继承关系中方法的重写体现多态
(2)虽然都是同一个方法,但是可以以一定的规则调用不同的方法,提高了代码的复用性
对象体现多态
(1) 一个对象的编译类型和运行类型,可以不一致
(2) 编译类型在定义对象时,就确定了,不能改变
(3) 运行类型是可以变化的
(4) 编译类型看定义时 = 号的左边,运行类型看 = 号的右边
总结:多态的体现就在于父类的引用(编译类型)可以接收(指向)子类的对象(运行类型),这样的好处在于方便统一管理,无需重复编写代码
向上转型
(1)语法:父类类型 引用名 = new 子类类型 ( ) ;
(2)特点:编译类型看左边,运行类型看右边
(3)可以调用父类中的所有成员(需要遵守访问权限限制),不能调用子类中特有的成员(能够调用哪些内容是由编译类型所决定的)
(4)最终运行效果看子类的具体实现
因为子类在等号右边,运行结果看运行类型
向下转型
(1)语法:子类类型 引用名 = (子类类型) 父类引用;
(2)只能强转父类的引用,不能强转父类的对象
(3)要求父类的引用必须指向的是当前目标类型的对象
(4)当向下转型后,可以调用子类类型中所有的成员
补充:调用的时候优先在本类中找,如果没有就找到父类,直到 Object
代码示例
java
// 父类
package poly;
public class animal {
public void run(){
System.out.println("调用animal类中的---run()方法");
}
public void eat(){
System.out.println("调用animal类中的---eat()方法");
}
public void show(){
System.out.println("调用animal类中的---show()方法");
}
public void get(){
System.out.println("调用animal类中的---get()方法");
}
}
// 子类
package poly;
public class cat extends animal{
public void run(){
System.out.println("调用cat类中的---run()方法");
}
public void eat(){
System.out.println("调用cat类中的---eat()方法");
}
public void show(){
System.out.println("调用cat类中的---show()方法");
}
public void print(){
System.out.println("调用cat类中的---print()方法");
}
}
// 主类
package poly;
public class main {
public static void main(String[] args) {
/*
说明
(1)父类和子类都有run(),eat(),show()方法
(2)父类独有get()方法,子类没有
(3)子类独有print()方法,父类没有
*/
//一、向上转型(可以调用父类的所有成员,但是不能调用子类的)
animal animal = new cat(); // 使用父类的引用接收子类的对象
animal.eat(); // 运行结果看子类,运行类型是cat,优先调用cat中的eat()方法
animal.run();
animal.show();
animal.get(); // 运行类型是子类cat,但是没有get()方法,于是找到父类中get()方法调用
// animal.print(); // 错误,无法调用子类
//二、向下转型(可以调用子类的所有成员)
cat cat = (cat)animal; // 原先用animal指向cat对象的堆空间,强转之后使用cat引用指向
cat.print();
}
}
//运行结果
调用cat类中的---eat()方法
调用cat类中的---run()方法
调用cat类中的---show()方法
调用animal类中的---get()方法
调用cat类中的---print()方法使用细节
1. 多态的前提是:类之间存在继承关系
2. Java 中,子类引用不可以指向父类,但是父类引用可以指向子类,这是由于继承关系的特性
3. 父类引用指向子类对象
(1)父类引用可以指向子类对象,因为子类是父类的扩展(除了拥有父类的内容以外,子类可以拥有自己的内容,但是父类不会拥有),子类对象是父类类型的一个实例。
(2)这时,父类引用只能访问父类中的方法和属性,不能访问子类特有的方法和属性(除非进行类型转换)。
4. 子类引用不能指向父类对象
(1)子类是父类的扩展,子类中可能有父类没有的属性和方法,编译器无法保证子类引用指向父类对象时访问的安全性。
(2)如果强行让子类引用指向父类对象,编译器会报错,除非进行强制类型转换并且确保类型安全(通过 instanceof 检查等方式)
