》多态其实就是多种形态,多种形式:
》两个最直接的体现
方法重写
方法重载
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成员变量,因而编译错误。
-
对象的多态性,只适用于方法,不适用于属性(编译和运行都看左边)
重载overload和重写override的区别
位置 方法名 参数列表 返回值 访问修饰符
方法重载 同一个类 相同 必须不同 无关 无关
方法重写 子类中重写父类方法 相同 必须相同 必须相同 不能比父类更严格
总结一下,方法的重载:
1.发生在同一个类中
2.方法名相同
3.参数列表不同(参数的类型,个数,顺序不同)
4.和返回值类型无关
5.和方法的修饰符列表无关
注:判断是否为重载,跟方法的权限修饰符、返回值类型、形参变量名、方法体都没有关系!
方法重写的规则
l 在继承关系的子类中
l 重写的方法名、参数、返回值类型必须与父类相同
l 私有方法不能继承因而也无法重写
但是选哪个重载版本在编译时就定了,运行时是根据唯一的方法签名去调用,而不像虚方法那样要先查表。这里的“名字”是方法签名。所以根本没有“同样的一个名字”,自然不是多态。
所以就看你把不把前一种多态(静态多态)也算进java语境下的多态里。