面向对象中的多态(未完)

首先什么是多态:多态就是父类引用指向子类对象.

多态的目的:接口重用

多态发生的情况:赋值的时候.

实现多态的条件:继承和实现,重写,父类引用指向子类对象,

      继承和实现:

      重写/覆盖:

      父类引用指向子类对象: 父类引用指向子类对象涉及两个名词,向上转型(upcasting) 、向下转型(downcasting).  

            举个例子:有2个类,Father是父类,Son类继承自Father。

                          Father f1 = new Son();    这就叫 upcasting (向上转型)

                          现在f1引用指向一个Son对象

                          Son s1 = (Son)f1;    这就叫 downcasting (向下转型)

                          第二个例子:

                          Father f2 = new Father();

                          Son s2 = (Son)f2;       // 出错,子类引用不能指向父类对象

                          你或许会问,第1个例子中:Son s1 = (Son)f1;问什么 是正确的呢。
                          很简单因为f1指向一个子类对象,Father f1 = new Son(); 子类s1引用当然可以指向子类对象了。
                          而f2 被传给了一个Father对象,Father f2 = new Father();子类s1引用不能指向父类对象。

           总结:
                  1。父类引用指向子类对象,而子类引用不能指向父类对象。
                  2。有向上转型,然后才有向下转型。
                  3。把子类对象直接赋给父类引用叫upcasting向上转型,向上转型不用强制转换。
                       如:Father f1 = new Son();
                  4。把指向子类对象的父类引用赋给子类引用叫向下转型(downcasting),要强制转换。
                       如:f1 就是一个指向子类对象的父类引用。把f1赋给子类引用s1即 Son s1 = (Son)f1;
                       其中f1前面的(Son)必须加上,进行强制转换。

多态涉及两块:类库端和客户端

     把子类转换成父类:子类型的对象的数据类型是父类型;(内存中按照父类型的类型划分一个内存空间,但是保存的指针指向子类型);
     数据类型转换的内部原理:程序分两个阶段,编译和运行,编译阶段;编译器只知道引用名的数据类型,运行的时候,实际指向的是堆中的实际数据类型的对象
     Animal a_1 = new Cat();
     程序在编译器阶段,a_1是animal类型;所以在编译阶段a_1引用绑定的是animal中的eat方法;程序在运行的时候,堆中的对象实际是cat类型,而cat已经重写了eat方法.所以程序在运行阶段绑定的是cat中的eat()方法(动态绑定);
     向上转型为什么是自动类型转换:因为扩展类肯定包含基类的接口,向上转型的缺点:可能丢失扩展类(子类)的新的(方法,属性);
     多态的根本点:接口的覆盖;成员方法的绑定是动态的,编译的时候不进行检查;在执行的时候,初始化(实例化)都完成以后在进行绑定
     关键用法:在客户端程序员,实例化对象以后(实例化,关键点),我们只需要一直调用基类的方法即可(这个也是后期,学习接口的基本原理)
     执行的时候却回去调用子类的方法;所以我们写的客户端业务流程类和和类库端的扩展类(子类)是完全没有关系的(绝对解耦);
     a_1.eat();  //猫的方法
     程序开发的流程:确定需求,项目设计,编码,测试,部署
     向下转型,需要强制类型转换
     为什么向下转型:因为有时候,我们需要调用子类中新的接口(就是方法,属性,都会包装成方法set(),get()),但是这样要保证我们的子类是正确的;所以,java中默认所有的强制类型转换都会进行检查,报错;
     但是强制类型转换需要先向上转型;(直接实例化的话,可以直接调用类,也就不需要向下转型了);在强制类型(向下)转换,如果没有过向上转型,就没有向下 转型;好处:不需要去实例化子类;因为在设计的时候就尽量避免了子类中出现新的接口(避免子类过多的出现父类中没有的方法),所以这种情况很少出现,向下 转型就是一种权宜之计而已(是因为有了向上转型,才有了向下转型)
      客户端(复用:调用)用类库类代码的两种方式:组合(new,实例化),继承(两者注意权限:泛化)
      尽量用组合,不用继承;如果用了继承,就尽量(向上转型)多态;如果要用到子类接口(方法),就向下转型
      有的时候,为了降低错误风险,我们需要先判断类之间的继承关系,向下转型的那个类是不是继承于我们的基类
      关键字 instanceof 扩展那个类(不是父类,是子类)(判断当前的这个父类引用变量指向的那个子类对象,和我们要转型成为的这个对象是不是同一个类实例化得来)
      返回真假(类继承很多,且不知道继承层次的时候,用两个名词好):确定变量是不是确定指向那个对象(说法有问题,上面一句说好了)
      因为,这个涉及程序初始化的问题;程序会从最低扩展类一直向根类初始化,然后在初始化回来,所以根类,到当前扩展类在堆内存中都是存在的

实现多态的几种方式:

      成员方法:在方法声明的形参列表中的是父类的,调用传值的时候是子类的对象引用

      构造方法:构造方法声明的时候,是父类传值的时候,是子类的对象引用

      直接实例化多态:声明的时候是父类,实例化的时候是子类对象的引用的

      成员变量的多态:成员变量声明为父类的,但是赋值的时候,是子类的对象引用

多态的作用(好处):

     增强代码的扩展能力,降低了对象间的耦合度,让对象间关联从基类开始一层层关联,越接近基类的关联越好
     业务逻辑代码(也就是控制器),本质是调用不同的对象完成工作,如果写得太是的话,每变一次都需要大的改动
     但是,每个子类都会继承父类的所有非构造方法,如果我们的逻辑代码是针对父类方法写的,那么无论子类怎么变,我们都会去调用父类方法,即使父类方法功能跟不上,在子类中进行   了重写,我们的程序在编译阶段也不会报错,但是在执行阶段,我们的程序会根据方法名,去调用实例化后的对象的成员方法,即我们改写以后的方法.
     这样就达到了,不改变业务逻辑代码的情况下,加强了性能
     ---------------------------------------------------------------------
     类库程序员和客户端程序员会更好理解一下
     由于项目速度的需要,类库程序员开始写的代码有很多应付的成分,会了加强性能,需要重写,只要我们写新的类,只要扩展基类,就不会有影响
     ----------------------------------------------------------------------
     New的时候为什么可以找到对象的类:找类是jvm虚拟机在文件系统中找,因为我们配置了classpath这个环境变量,所以他会按照classpath的路径挨个排找,最后找不到就报错,最开始我们配置的是./就是先从当前目录下找,再到tools找

以下有一个简单明了的多态知识架构

原文地址:https://www.cnblogs.com/lwxalxy/p/4684637.html