摘要:多态性面向对象三大特性封装继承多态。面向对象多态性存在的三个必要条件继承重写父类引用指向子类对象多态性的实现方式重写与重载静态多态性方法重载方法重载允许类具有多个相同名称的方法,但是方法参数列表不同。
多态性
面向对象(OOP)三大特性:封装、继承、多态。
多态性(polymorphism)指同一行为具有多种不同表现形式,在面向对象程序设计中表现为同一消息可以根据发送对象的类型不同,做出多种不同的行为。
多态性的优点
多态性能够从一定程度上消除类型之间的耦合关系,通过统一接口方式,不同类的对象可以直接替换,程序更加灵活,可扩展。
面向对象多态性存在的三个必要条件
继承
重写
父类引用指向子类对象
多态性的实现方式 重写(Override)与重载(Overload) 静态多态性:方法重载(Method Overloading)方法重载(Method Overloading)允许类具有多个相同名称的方法,但是方法参数列表不同。
重载形式:
case 1: 参数数量变化(有效)
add(int, int) add(int, int, int)
case 2: 参数数据类型变化(有效)
add(int, int) add(int, float)
case 3: 参数数据类型顺序变化(有效)
add(int, float) add(float, int)
bad case 1: 仅改变返回类型(无效)
int add(int, int) float add(int, int)
Java 方法签名由方法名称和其后的参数列表共同决定,仅改变返回类型编译器无法重载。 不过方法重载(Method Overloading)允许改变返回类型和存取权限,但两者不属于方法签名。
方法重载(Method Overloading)式多态性,即方法调用取决于调用时传递的参数(数量、类型、顺序),属于编译时静态多态性。
动态多态性:方法重写(Method Overriding)方法重写(Method Overriding)允许子类对父类可以访问的方法,实现自定义行为,但是方法签名需要保持一致。重写的优点在于,无需修改父类代码即可改变子类继承的方法。
重写形式:
重写依赖继承,通过父类引用,指向子类对象实现动态多态性。
public class Animal{ public void sound(){ System.out.println("Animal is making a sound"); } } public class Cat extends Animal{ @Override public void sound(){ System.out.println("Meow"); } public static void main(String args[]){ Animal obj = new Cat(); obj.sound(); } }
输出:
Meow
重写(覆盖)规则:
方法签名(方法名称和参数列表)必须一样,返回类型需要兼容。
不能降低方法的存取权限。
static, private, final 标记的方法以及类的构造方法不能被重写(覆盖)。
分析原因:
Java 通过方法签名标识方法,因此重写需要确保是子类继承自父类的同一方法。
子类不可以降低父类方法的存取权限(可见性),但可以升级。继承反映一种 “is a” 关系,子类是父类,支持父类所有对外开放的行为。降低方法的存取权限,使得父类作为统一接口方式调用方法的能力被破坏。
private, final 标记的方法以及父类的构造方法无法继承,故无法重写。
static 标记的方法为静态方法属于类,通过类名.方法名形式调用,无需依赖对象。
静态方法和属性会被子类继承,子类同样允许定义同名静态方法和属性,区别于实例方法“重写”和属性“重名”,这种情况被称为“隐藏”。此时子类中调用同名的父类静态方法和属性,需要指明父类名.方法名或父类名.变量名。
多态性的类型可以分为运行时和编译时,方法重写(Method Overriding)代表运行时动态多态性,方法重载(Method Overloading)代表编译时静态多态性。
方法调用与方法体的关联称为绑定,有两种类型的绑定:在编译时发生的静态绑定(Static Binding or Early Binding)和在运行时发生的动态绑定(Dynamic Binding or Late Binding)。
static, private, final 标记的方法以及类的构造方法是静态绑定的,在编译时确定所属类的类型,因此这些方法无法覆盖。其他非标记的方法可以称为“虚函数”,Java 中其实并没有“虚函数”的概念,所有普通函数(方法)默认都相当于 C++ 的”虚函数”允许覆盖(Override),因此虚函数(Virtual Method)能够根据运行时具体对象的类型进行动态绑定实现动态多态性,例如方法重写(Method Overriding)。
静态绑定示例:
class Human{ public static void walk() { System.out.println("Human walks"); } } class Boy extends Human{ public static void walk(){ System.out.println("Boy walks"); } public static void main( String args[]) { /* Reference is of Human type and object is * Boy type */ Human obj = new Boy(); /* Reference is of Human type and object is * of Human type. */ Human obj2 = new Human(); obj.walk(); obj2.walk(); } }
输出:
Human walks Human walks
声明为 static 的方法不能被重写,但是能够被再次声明(隐藏)。
Static Binding vs Dynamic Binding
静态绑定发生在编译时,而动态绑定发生在运行时。
静态绑定使用的是类信息:类的类型决定调用方法,而动态绑定使用的是对象信息:对象的类型决定调用方法。
方法重载使用静态绑定,而方法重写使用动态绑定。
综合练习多态性示例程序:
class A { public String show(D obj) { // 方法一 return ("A and D"); } public String show(A obj) { // 方法二 return ("A and A"); } } class B extends A { public String show(B obj) { // 方法三 return ("B and B"); } public String show(A obj) { // 方法四 return ("B and A"); } } class C extends B { } class D extends B { } public class Main { public static void main(String[] args) { A a1 = new A(); A a2 = new B(); B b = new B(); C c = new C(); D d = new D(); System.out.println("1--" + a1.show(b)); System.out.println("2--" + a1.show(c)); System.out.println("3--" + a1.show(d)); System.out.println("4--" + a2.show(b)); System.out.println("5--" + a2.show(c)); System.out.println("6--" + a2.show(d)); System.out.println("7--" + b.show(b)); System.out.println("8--" + b.show(c)); System.out.println("9--" + b.show(d)); } }
运行结果:
1--A and A 2--A and A 3--A and D 4--B and A 5--B and A 6--A and D 7--B and B 8--B and B 9--A and D
详细分析:
A、B、C、D 各类继承关系如图所示:
A a1 = new A(); 正常创建对象 a1,涉及函数重载 show(),a1 具有调用方法一 show(D obj) 和方法二 show(A obj) 的能力。
a1.show(b) 由编译器进行静态绑定(前期绑定)方法二 show(A obj)。
a1.show(c) 由编译器进行静态绑定(前期绑定)方法二 show(A obj)。
a1.show(d) 由编译器进行静态绑定(前期绑定)方法一 show(D obj)。
A a2 = new B(); 多态创建父类引用,指向子类对象,a2 向上转型具有调用 A 类方法一 show(D obj) 和方法二 show(A obj) 的能力,其中子类 B 重写父类 A 的方法二 show(A obj) 为方法四 show(A obj)。记住向上转型存在缺点,即不能调用子类中有,父类没有的方法,如方法三 show(B obj)。
a2.show(b) 运行时动态绑定(后期绑定)方法四 show(A obj)。
a2.show(c) 运行时动态绑定(后期绑定)方法四 show(A obj)。
a2.show(d) 由编译器进行静态绑定(前期绑定)方法一 show(D obj)。
B b = new B(); 正常创建对象 b,涉及函数重载 show(),b 具有调用方法三 show(B obj) 和方法四 show(A obj) 的能力。同时 B 继承自 A 因此拥有方法一 show(D obj) 和方法二 show(A obj) 其中方法二被方法四重写覆盖。
b.show(b) 由编译器进行静态绑定(前期绑定)方法三 show(B obj)。
b.show(c) 由编译器进行静态绑定(前期绑定)方法三 show(B obj)。
b.show(d) 由编译器进行静态绑定(前期绑定)方法一 show(D obj)。
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/71578.html
摘要:很多情况下,通常一个人类,即创建了一个具体的对象。对象就是数据,对象本身不包含方法。类是相似对象的描述,称为类的定义,是该类对象的蓝图或原型。在中,对象通过对类的实体化形成的对象。一类的对象抽取出来。注意中,对象一定是通过类的实例化来的。 showImg(https://segmentfault.com/img/bVTJ3H?w=900&h=385); 马上就要到七夕了,离年底老妈老爸...
摘要:很多情况下,通常一个人类,即创建了一个具体的对象。对象就是数据,对象本身不包含方法。类是相似对象的描述,称为类的定义,是该类对象的蓝图或原型。在中,对象通过对类的实体化形成的对象。一类的对象抽取出来。注意中,对象一定是通过类的实例化来的。 showImg(https://segmentfault.com/img/bVTJ3H?w=900&h=385); 马上就要到七夕了,离年底老妈老爸...
摘要:很多情况下,通常一个人类,即创建了一个具体的对象。对象就是数据,对象本身不包含方法。类是相似对象的描述,称为类的定义,是该类对象的蓝图或原型。在中,对象通过对类的实体化形成的对象。一类的对象抽取出来。注意中,对象一定是通过类的实例化来的。 showImg(https://segmentfault.com/img/bVTJ3H?w=900&h=385); 马上就要到七夕了,离年底老妈老爸...
摘要:方法即为收集器,它接收高阶函数和的后端掘金年的第一天,我坐在独墅湖边,写下这篇文章。正因如此,所以最全系列教程后端掘金是从版本开始引入的一个新的,可以替代标准的。 设计模式之单例模式 - 掘金前言 作为一个好学习的程序开发者,应该会去学习优秀的开源框架,当然学习的过程中不免会去阅读源码,这也是一个优秀程序员的必备素养,在学习的过程中很多人会遇到的障碍,那就是设计模式。很多优秀的框架会运...
阅读 1554·2021-11-04 16:11
阅读 3283·2021-09-09 11:33
阅读 1544·2019-08-30 15:54
阅读 602·2019-08-30 15:44
阅读 3148·2019-08-30 15:43
阅读 2490·2019-08-30 13:06
阅读 1683·2019-08-29 17:00
阅读 871·2019-08-29 15:33