多态的深层次理解-多态的两个最直接的体现:方法重写和方法重载

》多态其实就是多种形态,多种形式:
》两个最直接的体现
方法重写
方法重载

java实现多态的方式:
1、在同一类中多个同名函数同时存在,具有不同的参数个数/类型,实现重载。
2、在继承关系中,实现同名函数的重写。子类中的方法与父类中的某一方法具有相同的方法名、返回类型和参数表,则新方法将覆盖原有的方法。

 重载是静多态,重写是动多态

多态的含义:

多态是指同一个方法的调用,由于对象的不同可能会有不同的行为。上述是一般对于多态的定义,实际上由于函数入口参数的不同也能构成多态,不过此处与前者定义不同之处在于不再强调对象不同。

两种不同时期的多态:

  • 编译时期多态:其又被称为静态多态,编译时期的多态是靠重载实现的,根据参数个数,类型和顺序决定的(必须在同一个类中
  • 运行时的多态:运行时期的多态是靠方法的重写实现的,在编译期间被视作相同方法,但是运行期间根据对象的不同调用不同的方法

对于重载而言,在方法调用之前,编译器就已经确定了所要调用的方法,这称为“早绑定”或“静态绑定” ;

对于重写,只有等到方法调用的那一刻, 解释运行器才会确定所要调用的具体方法,这称为“晚绑定”或“动态绑定” 。

多态的作用:消除类型之间的耦合关系。提高了代码的通用性,常称作接口重用

抽象类和接口都是为多态服务的

对象的多态性:父类的引用指向子类的对象(或子类的对象赋给父类的引用)

  • 可以直接应用在抽象类和接口上

虚拟方法调用

有了对象的多态性以后,我们在编译期,只能调用父类中声明的方法,但在运行期,我们实际执行的是子类重写父类的方法

总结:编译,看左边;运行,看右边。

Java引用变量有两个类型: 编译时类型和运行时类型。 编译时类型由声明该变量时使用的类型决定运行时类型由实际赋给该变量的对象决定。 简称: 编译时, 看左边;运行时, 看右边。

  • 若编译时类型和运行时类型不一致, 就出现了对象的多态性(Polymorphism)

  • 多态情况下, “看左边” : 看的是父类的引用(注意父类中不具备子类特有的方法);“看右边” : 看的是子类的对象(实际运行的是子类重写父类的方法)

  • 一个引用类型变量如果声明为父类的类型,但实际引用的是子类对象,那么该变量就不能再访问子类中添加的属性和方法

    Student m = new Student();
    m.school = “pku”; //合法,Student类有school成员变量
    Person e = new Student();
    e.school = “pku”; //非法,Person类没有school成员变量
  • 属性是在编译(将java代码编译成class二进制文件)时确定的,编译时e为Person类型,没有school成员变量,因而编译错误。

  • 对象的多态性,只适用于方法,不适用于属性(编译和运行都看左边)

对于Parent p = new Child();这样的多态形式,p.成员变量,p.静态的,编译运行都是参考左边,即Parent;
而p.成员函数的形式,编译参考左边(Parent),运行则参考右边(Child)。
                重载overload和重写override的区别
                位置                    方法名    参数列表    返回值        访问修饰符
    方法重载    同一个类                相同    必须不同    无关        无关
    方法重写    子类中重写父类方法        相同    必须相同    必须相同    不能比父类更严格
    

总结一下,方法的重载:

1.发生在同一个类中

2.方法名相同

3.参数列表不同(参数的类型,个数,顺序不同)

4.和返回值类型无关

5.和方法的修饰符列表无关

注:判断是否为重载,跟方法的权限修饰符、返回值类型、形参变量名、方法体都没有关系!

方法重写的规则
l 在继承关系的子类中
l 重写的方法名、参数、返回值类型必须与父类相同
私有方法不能继承因而也无法重写

多态说的就是“同样的一个名字指代多个东西”。编写时来看,重载当然算多态。这里的“名字”是方法名,“东西”是重载版本。
但是选哪个重载版本在编译时就定了,运行时是根据唯一的方法签名去调用,而不像虚方法那样要先查表。这里的“名字”是方法签名。所以根本没有“同样的一个名字”,自然不是多态。
所以就看你把不把前一种多态(静态多态)也算进java语境下的多态里。