多态

84 阅读5分钟

多态的由来

    多态在面向对象中的含义:相同的行为,不同的实现。

    相同的行为的体现:

        1、多态是描述行为的,也就是方法;

        2、相同行为其实在本质上就是“同名”方法。

    不同的实现:

        同名的方法,但是个各自有各自的方法实现体,也就是“{}”及其里面的代码不同。

    封装在面向对象中体现的是“归纳”和“信息的隐藏”;

    继承在面向对象中体现的是“复用性”和“is-a关联”;

    多态在面向对象中体现的是“丰富度”。

多态的分类

    “静态多态”与“动态多态”

        这里的“静态”和static关键字没有任何关系。

        这里的“静”指的是在编译期就能够确定对象到底调用的是哪个方法;

    “动”指的是程序必须在运行期才能够根据具体绑定的对象从而知道要调用的是哪个方法。

        前面我们所学过的“重载”或者单独使用“重写”都属于“静态多态”。而要做“动态多
        
    态”,需要两种技术的结合:“重写”和“动态绑定”。

转型技术

    所谓的“转型技术”就是类型转换。比如“自动类型”转换和“强制类型”转换。

    1、转换的依据

        要求:小类型的可以直接自动转换为大类型的。

        这里的“小”指的是?“大”指的是?

        指的是*该类型能够表示的数据范围谁大谁小。*,而这个范围的大小是由基本数据类
        
        型的字节空间和存放形式配合起来的。

    2、转换的规则

        前提---boolean不参与数据类型转换

        范围小的基本数据类型 自动转换成 范围大的基本数据类型。

        范围大的基本数据类型 强制转换成 范围小的基本数据类型。

        语法: 小类型变量 = (小类型)大类型的数据。

    2-1、如果不使用强转语法,编译不通过;

    2-2、如果使用强转语法,可能会有精度的丢失;

引用数据类型其实也能做强转或自动转

    1、转换的依据

        “小类型”的自动转换为“大类型”;

        “大类型”的要强制转换为“小类型”。

        这里的范围是必须在“继承关系”下进行探讨,父类(超类)代表的范围比子类(派生
        
        类)要大。只有这种情况下“大小”关系才是明确的,可以讨论的。

    2、转换规则

        *只有有继承关系的类才能够做转换,兄弟姐妹类都不允许。*

    2-1、自动类型转换

        在引用数据类型转换当中,这种又被称为**向上转型**。因为它是沿着继承树往上走。

            ```java

                Pet p = new Dog();

            ```

    2-2、强制类型转换

        又被称之为**向下转型**。

            ```java

                Cat c = (Cat)new Pet();

            ```

    在引用数据类型当中,强转仍然有风险。而它的风险就不仅仅是精读丢失了,而是运行时报
    
    “ClassCaseException” --- 类型转换异常!!!

引用数据类型转换的本质

    1、强转也好,自动转换也好,都不是改变对象本身,而只是换一个类型的引用变量去指向这个对象。

    2、编译通不通过或运行通不通过,依据是这个引用变量的类型和对象类型是否匹配。

       本质上只有两种情况是没有问题的:

       2-1、本类引用指向本类对象;

       2-2、父类引用指向子类对象。

    从面向对象场景中解释:我们说“一个动物是一只猫对象”这是完全正确的。

    从内存当中解释:每一个子类对象身上有一个完整的父类对象部分,所以用父类引用指过去
    
    是可以看到一个父类对象的完整内容的,因此没有问题。   

父类引用指向子类对象有何特点

    1、父类引用指向子类对象后,只能看到来自于父类当中的属性或行为(当然要受访问修饰符的限制)。

    2、如果这个行为被子类重写了,那么父类引用看到的这个行为,执行的效果是子类重写后的效果。

父类引用指向子类对象后的弊端

    由于变量的类型是父类类型,虽然指向了子类对象,但是在用变量做"."操作的时候,只能
    
    看到子类对象身上从父类继承而来的属性或方法,看不到子类特有的属性或方法。

    解决方案:

        第一步:通过强转,把父类的引用赋值给一个子类类型的变量。这样这两个引用都是指
        
    向的同一个对象,而父类类型变量能看到继承而来的属性和行为,子类类型的变量能看到所
    
    有的属性和行为。

        第二步:强转是有风险的,而且引用类型的风险是运行时异常,它会导致程序停止运行
        
    直接报错。所以,在强转前,我们必须通过判断,保证传进来的是一个可以被强转的类型。

instanceof

    instanceof 是一个关键字,同时它也是一个运算符!它是一个boolean运算符!

        书写格式: 对象 instanceof 类型

    在强转之前,一定要用instanceof做一次判断,确实该对象确实属于某个类型的时候,才能做强转。
    
        由于现在我们知道了父类引用可以指向子类对象,所以当我们拿到一个父类引用的时
        
    候,并不知道它到底指的是那个类型的对象。有可能是父类对象,也有可能子类A的对象,
    
    或子类B的对象,那么instanceof就可以帮我们判断它到底指的是谁!!!

多态参数

    当一个方法需要接收参数的时候,我们把形参的类型设计为父类类型,那么该父类下的所有
    
    子类对象都可以作为参数传递进来。

    当然实际使用当中,不一定是参数用父类类型的变量;属性也可以......