自学Java之day10_java之多态性

多态的概述

多态是继封装、继承之后,面向对象的第三大特性。 生活中,比如跑的动作,小猫、小狗和大象,跑起来是不一样的。再比如飞的动作,昆虫、鸟类和飞机,飞起来也 是不一样的。可见,同一行为,通过不同的事物,可以体现出来的不同的形态。多态,描述的就是这样的状态。一个对象拥有多种形态,这就是对象的多态性。例如:小明是一个学生(学生形态),但也是一个人(人类形态)。

定义

多态: 是指同一行为,具有多个不同表现形式。

前提

  • 继承或者实现【二选一】
  • 方法的重写【意义体现:不重写,无意义】
  • 父类引用指向子类对象【格式体现】

多态的体现

多态体现的格式:

  • 父类名称 变量名 = new 子类对象;

或者

  • 接口名称 对象名 = new 实现类名称();

多态中成员变量的访问特点

访问成员变量的两种方式:

  • 直接通过对象名称访问成员变量名称:看等号左边是谁,优先用谁,没有则向上找。
  • 间接通过成员方法访问成员变量名称:看该方法属于谁,优先用谁,没有则向上找。

多态中的成员方法的访问特点

当使用多态方式调用方法时,首先检查父类中是否有该方法,如果没有,则编译错误;如果有,执行的是子类重写 后方法  口诀:编译看左边,运行看右边。

在多态的代码当中,成员方法的访问规则是:看new的是谁,就优先用谁,没有则向上找。

对比:

  • 成员变量:编译看左边,运行还看左边。
  • 成员方法:编译看左边,运行看右边。

代码举例

定义父类Father

package myDemo02;

public class Father {
    //定义成员变量
    String name = "张三";
    //定义成员方法
    public void method() {
        System.out.println();
        System.out.println("我是父类中的方法");
    }

    public void methodFather() {
        System.out.println("我是父类中独有的方法,我的名字是" + name);
    }

}

定义子类Son

package myDemo02;

public class Son extends Father {
    //定义子类成员变量
    String name = "李四";
    @Override
    //重写父类的成员方法
    public void method() {
        System.out.println("我重写了父类中的方法,我的名字是:" +name);

    }
}

定义测试类MyMultiTest

package myDemo02;

public class  {
    public static void main(String[] args) {
        /*父类类型 变量名 = new 子类对象;
         父类类型:指子类对象继承的父类类型,或者实现的父接口类型。
        */
        //多态写法
        Father multi = new Son();
        //调用子父类重名的方法,编译看父类,实际运行子类中的方法,
        multi.method();
        //调用父类中独有的方法:编译看父类,因为子类中没有相同的方法,所以向上查找
        multi.methodFather();
        //访问子父类重名成员变量,等号左边的是谁,优先使用谁的成员变量
        String name = multi.name;
        System.out.println(name);
    }
}

代码执行后的结果

多态的好处

实际开发的过程中,父类类型作为方法形式参数,传递子类对象给方法,进行方法的调用(多态规定,执行的是子类重写的方法),更能体现出多态的扩展 性与便利。

引用类型转换

多态的转型分为向上转型与向下转型两种:

向上转型

向上转型:多态本身是子类类型向父类类型向上转换的过程,这个过程是默认的。 当父类引用指向一个子类对象时,便是向上转型。 向上转型一定是安全的。

使用格式:父类类型 变量名 = new 子类类型();  

含义:创建一个子类对象,把它当做父类来看待使用

例如

// 创建了一个dog对象,把它看成是动物,没有如何问题
      Animal animal = new Dog();

向下转型

向下转型:父类类型向子类类型向下转换的过程,这个过程是强制的。 一个已经向上转型的子类对象,将父类引用转为子类引用,可以使用强制类型转换的格式,便是向下转型。

使用格式:子类类型 变量名 = (子类类型) 父类变量名;

含义:将父类对象还原成为本来的子类对象

例如:

//将动物对象,还原成为本来的dog对象 
Dog dog = (Dog) animal;

注意事项:

必须保证对象创建的时候就dog对象,才能向下转型为dog。否则运行时,却报出了 ClassCastException ,类型转换异常!

为什么要转型

当使用多态方式调用方法时,首先检查父类中是否有该方法,如果没有,则编译错误。也就是说,不能调用子类拥 有,而父类没有的方法。编译都错误,更别说运行了。这也是多态给我们带来的一点"小麻烦"。所以,想要调用子 类特有的方法,必须做向下转型。

向下转型容易发生的问题

如果创建了A 对象,却把它向下转型成为B 对象,在运行时,会报出了 ClassCastException ,类型转换异常!为了避免ClassCastException的发生,Java提供了 instanceof 关键字,给引用变量做类型的校验,格式如下:

  • 变量名 instanceof 数据类型
  • 如果变量属于该数据类型,返回true
  • 如果变量不属于该数据类型,返回false

代码举例

定义接口Animal

package myDemo04;
//定义接口
public interface Animal {
    //定义抽象方法
    public abstract void eat();
}

定义实现类Cat

package myDemo04;

public class Cat implements  Animal{
    @Override
    public void eat() {
        System.out.println("我喜欢吃鱼");
    }
    public void CatRun(){
        System.out.println("我是猫,跑起来没有声音");
    }
}

定义实现类Dog

package myDemo04;

public class Dog implements Animal {
    @Override
    public void eat() {
        System.out.println("我喜欢吃骨头");
    }
    public void DogRun(){
        System.out.println("我是狗,跑的好快好快");
    }
}

定义测试类

package myDemo04;

public class Test {
    public static void main(String[] args) {
        //父类引用指向子类对象就是向上转型:
        Animal animal = new Dog();
        //调用方法,编译看左,运行看右
        animal.eat();
        //  Cat cat = (Cat) animal;创建了Dog对象,转换为Cat对象,运行会报ClassCastException ,类型转换异常!
        if (animal instanceof Dog) {
            //将父类引用转为子类引用,便是向下转型。
            Dog dog = (Dog) animal;
            //调用子类中特有的方法
            dog.DogRun();
        }
        if (animal instanceof Cat) {
            //将父类引用转为子类引用,便是向下转型。
            Cat cat = (Cat) animal;
            //调用子类中特有的方法
            cat.CatRun();
        }

    }
}

代码执行后的结果

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章