一、概念
多态是面向对象设计的一个重要特征,是同一种事物的多种表现形式,可以把多种子类都当作父类型,进而屏蔽不同子类对象之间的差异,统一调用标准。
二、特点
多态的前提是存在继承关系,并且子类重写父类的方法,然后通过父类引用指向子类的对象,然后通过调用父类方法的声明,通过在子类中相同方法的重写的实现来实现功能。简而言之就是调用的是父类的声明,以及子类的实现,编译(保存)看左边,运行(测试)看右边。
例如:
1.创建父类Animal
class Animal {
public void eat() {
//创建父类中的普通方法eat
System.out.println("小动物animal吃啥都行!");
}
}
2.创建子类Cat
class Cat extends Animal{
//父类方法的重写
public void eat() {
System.out.println("小猫cat爱吃小鱼干!"); }
//创建子类特有的功能
public void jump() {
System.out.println("小猫cat跳的老高了!");
}
}
3.创建对象
public static void main(String[] args) {
Animal a = new Animal();
a.eat(); Cat c = new Cat();
c.eat();
//a.jump();父类无法使用子类的特有功能
c.jump();
//创建多态对象进行测试
Animal a1 = new Cat(); a1.eat();//eat()使用的是父类的声明,但是功能使用的功能是子类的功能
Animal a3 = new Dog(); a3.eat();
}
创建多态对象 Animal a1 = new Cat(); 调用eat()方法时,输出的是子类中的eat()方法中的打印语句,这是否说明调用的是子类的eat()方法呢?其实不是,它调用的还是父类的eat()方法,因为当你将父类中的eat()删除的时候,这句语句会报错,提示找不到eat()方法,这就表明,它调用的还是父类的方法,但是为什么输出的却是子类的打印语句呢?这就是之前多态的特点之一,调用的是父类方法的声明&子类方法的实现。
三、作用
当创建多态对象后 Animal a1 = new Cat(); 对于a1这个对象,调用同名的成员变量、成员方法以及静态成员时,到底调用的是父类的还是子类的呢?
1)成员变量:父类
2)成员方法:父类的声明&子类的实现
3)静态方法:如果父子类有同名的静态方法,使用的是父类的。
其实调用的都是父类的东西,只不过在成员方法中,虽然调用的是父类的声明,但是却是调用子类的实现,所以才能造成调用子类方法的假象。
注意!!!静态资源属于类资源,不存在重写的现象 ,只是两个类中有同样的声明方法而已,不属于重写
多态有一个最重要的作用就是将多种子类的对象的通过父类声明来统一化。Animal a1 = new Cat(); Animal a2 = new Dog();例如这两个对象a1和a2,你将鼠标悬浮在这两个对象上面的时候,会显示是Animal类的对象,当其要作为参数回传的时候,只需要在方法的参数列表添加Animal类型的对象就可以了,而不需要写两个方法,一个参数添加Cat类型的对象,一个添加Dog类型的对象,还有一种情况,如果这个Animal类又被一些新类继承,就又要多写一个方法来回传新的对象,而通过多态,就可以大大提高程序的可扩展性和可维护性。
多态还有一个最经典的使用,就是咱接下来要讲的异常机制里面,我们稍后再讲。
四、异常
异常是一些用来封装错误信息的对象它由异常的类型、提示信息、报错的行号提示三部分组成
异常一般有两种处理方式,一种是捕获异常,一种是向上抛出异常。当一个方法抛出异常,调用位置可以不做处理继续向上抛出,也可以捕获处理异常。
1.捕获异常
try{ 需要捕获异常的代码 }catch(异常类型 异常名){ 处理方案 }
2.抛出异常
在可能会会发生异常的方法上添加代码:throws 异常类型
public static void main(String[] args) throws Exception{ }
注意:
1.在捕获异常的时候,在catch里面填写异常的类型和异常名字,可以填写具体的异常类型名称,例如:InputMismatchException、ArithmeticException等,也可以填写他们的父类类型:Exception,这就是上面咱说得到的多态的最经典的使用,咱们可以不考虑具体的异常类型,通过父类类型来表述。只要是可以解决的异常,都是exception的子类,多态会把这些异常当作父类型来看,进而捕获,使用通用异常的解决方案来解决
2.如果在捕获异常的时候,想要捕获多个异常,可以在catch后面再继续加catch。
3.我们不能一直抛出异常,一般会在main()方法调用之前捕获解决异常,而不是把问题抛给main() ,因为到了main()没人解决了,异常还是会出现。