java 面向对象 三大特性 ---- 多态
多态:
一个指令,多重状态;
实现的功能,大家都去做一件事情;
java 多态的实现:
1. 必须实现继承;
2. 子类重写了父类的方法
3. 父类型的引用(变量)指向了,子类的对象; 运行时使用的子类对象;
多态的优势:
简化了代码的书写;
多态实现的实际情况:
https://www.cnblogs.com/startRuning/p/5673485.html
那么到底JVM是怎么指向Latin类中play()的呢?为了解决这个问题,JAVA使用了后期绑定的概念。当向对象发送消息时,在编译阶段,编译器只保证被调用方法的存在,并对调用参数和返回类型进行检查,但是并不知道将被执行的确切代码,被调用的代码直到运行时才能确定。
拿上面代码为例,JAVA在执行后期绑定时,JVM会从方法区中的Latin方法表中取到Latin对象的直接地址,这就是真正执行结果为什么是Latin.play的原因,在解释方法表之前,我们先了解一下绑定的概念。
将一个方法调用同一个方法主体关联起来被称作绑定,JAVA中分为前期绑定和后期绑定(动态绑定或运行时绑定),在程序执行之前进行绑定(由编译器和连接程序实现)叫做前期绑定,因为在编译阶段被调用方法的直接地址就已经存储在方法所属类的常量池中了,程序执行时直接调用,具体解释请看最后参考资料地址。
后期绑定含义就是在程序运行时根据对象的类型进行绑定,想实现后期绑定,就必须具有某种机制,以便在运行时能判断对象的类型,从而找到对应的方法,简言之就是必须在对象中安置某种“类型信”,JAVA中除了static方法、final方法(private方法属于)之外,其他的方法都是后期绑定。后期绑定会涉及到JVM管理下的一个重要的数据结构——方法表,方法表以数组的形式记录当前类及其所有父类的可见方法字节码在内存中的直接地址。
动态绑定具体的调用过程为:
1.首先会找到被调用方法所属类的全限定名
2.在此类的方法表中寻找被调用方法,如果找到,会将方法表中此方法的索引项记录到常量池中(这个过程叫常量池解析),如果没有,编译失败。
3.根据具体实例化的对象找到方法区中此对象的方法表,再找到方法表中的被调用方法,最后通过直接地址找到字节码所在的内存空间。
最后说明,域和静态方法都是不具有多态性的,任何的域访问操作都将由编译器解析,因此不是多态的。静态方法是跟类,而并非单个对象相关联的。对动态绑定还有不明白的请看资料链接,个人感觉分析的很到位
每次调用方法都要进行搜索,时间开销太大,所以虚拟机预先为每个类创建一个方法表(method table),其中列出了所有方法的签名和实际调用的方法。这样在调用方法的时候,只需要查找这个表即可。