多态

1、多态的基础是封装、继承

2、方法的多态:重载、重写

3、对象的多态

(1)前提:两个对象(类)存在继承关系

(2)一个对象的编译类型和运行类型可以不一致

(3)编译类型在定义对象时,就确定了,不能更改

(4)运行类型可以更改

(5)“=”的左方:编译类型;“=”的右方:运行类型

 

多态的向上转型

父类类型 父类引用名 = new 子类类型();

1、本质:一个子类对象直接赋给一个父类的引用变量,无需任何类型转换,即父类引用指向子类对象

2、在遵循访问权限的前提下,可以调用父类所有非重写成员,及子类所有重写成员,不能调用子类特有成员

3、编译阶段,编译类型决定可调用的成员,即能不能做,从顶级类向下查找,直到父类

4、运行阶段,运行类型决定具体实施,即怎么做,由创建的子类类型决定

Father father = new Son1();//编译类型:Father,运行类型:Son1
father = new Son2();//编译类型不变,运行类型:Son2

 

多态的向下转型

子类类型 子类引用名 = (子类类型) 父类引用名;

1、本质:一个父类对象赋给子类引用,并将父类对象强制转换成子类类型,即改变了运行类型

2、是强制转换父类的引用,而不是强制转换父类的对象实例

3、可以调用子类所有成员

4、向下转型是配合向上转型的,父类引用必须指向当前目标类型的对象,即父类引用指向对象的类型与要强制转换的类型一致

Father father = new Son1();
Son1 son1 = (Son1) father;
Son2 son2 = (Son2) father;

(1)Son2 son2 = (Son2) father; 不成立,运行时抛出 ClassCastException(强制类型转换异常)

(2)父类引用 father、子类引用 son1 指向同一个 Son1 对象,即向下转型后,父类引用仍存在

5、属性不能被重写,由编译类型决定调用的属性

6、比较操作符:instanceof,判断对象的运行类型是否为某类或某类的子类,返回 boolean 值

引用名 instanceof 类名

(1)若父类引用指向子类对象,在向下转型的过程中是安全的,编译阶段不会出错

(2)若父类引用指向父类对象,在向下转型的过程中是不安全的,编译阶段不会出错,但运行阶段会抛出 ClassCastException(强制类型转换异常),一般使用 instanceof 先验证,再向下转型

 

多态应用

1、多态数组(向上转型):数组定义时,编译类型为父类类型,允许保存的元素为子类类型

2、多态参数(向上转型):方法定义时,形参类型为父类类型,允许实参是形参的子类类型

 

动态绑定机制

1、调用对象方法时,该方法与该对象的运行类型(内存地址)绑定

2、调用对象属性时,不存在动态绑定机制,由编译类型决定调用的属性

3、当有多个重名函数时,在决定要调用哪个函数的过程中,首先按照参数类型进行匹配,即寻找在所有重载版本中最匹配的,然后才看变量的动态类型,进行动态绑定

 

理解方法调用

1、下面假设要调用 x.f(args),隐式参数 x 声明为类 C 的一个对象。下面是调用过程的详细描述

2、编译器查看对象的声明类型和方法名

(1)需要注意的是:有可能存在多个名字为 f 但参数类型不一样的方法

(2)例如,可能存在方法 f(int) 和方法 f(String)。编译器将会一一列举 C 类中所有名为 f 的方法和其超类中所有名为 f 而且可访问的方法(超类的私有方法不可访问)

(3)至此,编译器已知道所有可能被调用的候选方法。

3、接下来,编译器要确定方法调用中提供的参数类型

(1)如果在所有名为 f 的方法中

(2)存在一个与所提供参数类型完全匹配的方法,就选择这个方法。这个过程称为重载解析(overloading resolution)

(3)例如,对于调用 x.f("Hello"),编译器将会挑选 f(String),而不是 f(int)。由于允许类型转换,int 可以转换成 double,等等,所以情况可能会变得很复杂

(4)如果编译器没有找到与参数类型匹配的方法,或者发现经过类型转换后有多个方法与之匹配,编译器就会报告一个错误

(5)至此,编译器已经知道需要调用的方法的名字和参数类型

4、静态绑定、动态绑定

(1)静态绑定在程序编译阶段即可决定,而动态绑定则要等到程序运行时

(2)实例变量、private 方法、static 方法 / 变量、final 方法都是静态绑定

(3)如果是静态绑定的方法,编译器将可以准确地知道应该调用哪个方法

(4)与此对应的是,如果要调用的方法依赖于隐式参数的实际类型,那么必须在运行时使用动态绑定

(5)静态绑定的方法不可被子类重写

5、程序运行并且采用动态绑定调用方法时,虚拟机必须调用与 x 所引用对象的实际类型对应的那个方法

(1)假设 x 的实际类型是 D,它是 C 类的子类

(2)如果 D 类定义了方法 f(string),就会调用这个方法;否则,将在 D 类的超类中寻找 f(string),以此类推

(3)每次调用方法都要完成这个搜索,时间开销相当大

(4)因此,虚拟机预先为每个类计算了一个方法表(methodtable),其中列出了所有方法的签名和要调用的实际方法

(5)在真正调用方法的时候,虚拟机仅查找这个表就行了

(6)在前面的例子中,虚拟机搜索 D 类的方法表,寻找与调用 f(sting) 相匹配的方法,这个方法既有可能是 D.f(string),也有可能是 x.f(String),这里的 X 是 D 的某个超类

(7)这里需要提醒一点,如果调用是 super.f(param),那么编译器将对隐式参数超类的方法表进行搜索

posted @   半条咸鱼  阅读(45)  评论(0编辑  收藏  举报
(评论功能已被禁用)
相关博文:
阅读排行:
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
点击右上角即可分享
微信分享提示