之前一直知道多态是什么东西,平时敲代码也经常用到多态,但一直没有真正了解多态底层的运行机制到底是怎么样的,这两天才研究明白点,特地写下来,跟各位同学一起进步,同时也希望各位大神指导和指正。

  多态的概念:同一操作作用于不同对象,可以有不同的解释,有不同的执行结果,这就是多态,简单来说就是:父类的引用指向子类对象。下面先看一段代码

 package polymorphism;

 class Dance {
public void play(){
System.out.println("Dance.play");
}
public void play(int i){
System.out.println("Dance.play" + i);
}
} class Latin extends Dance {
public void play(){
System.out.println("Latin.play");
}
public void play(char c){
System.out.println("Latin.play" + c);
}
}
class Jazz extends Dance {
public void play(){
System.out.println("Jazz.play");
}
public void play(double d){
System.out.println("Jazz.play" + d);
}
}
public class Test {
public void perform(Dance dance){
dance.play();
}
public static void main(String[] args){
new Test().perform(new Latin()); // Upcasting
}
}

  执行结果:Latin.play。这个时候你可能会发现perform()方法里面并没有类似“if 参数类型 = Dance/Latin”这样的判断,其实这就是多态的特性,它消除了类型之间的耦合关系,令我们可以把一个对象不当做它所属的特定类型来对待,而是当做其基类的类型来对待。因为上面的Test代码完全可以这么写:

 public class Test {
public void perform(Latin dance){
dance.play();
}
public void perform(Jazz dance){
dance.play();
}
public static void main(String[] args){
new Test().perform(new Latin()); // Upcasting
}
}

但是这样你会发现,如果增加更多新的类似perform()或者自Dance导出的新类,就会增加大量的工作,而通过比较就会知道第一处代码会占优势,这正是多态的优点所在,它改善了代码的组织结构和可读性,同时保证了可扩展性。

  那么到底JVM是怎么指向Latin类中play()的呢?为了解决这个问题,JAVA使用了后期绑定的概念。当向对象发送消息时,在编译阶段,编译器只保证被调用方法的存在,并对调用参数和返回类型进行检查,但是并不知道将被执行的确切代码,被调用的代码直到运行时才能确定。拿上面代码为例,JAVA在执行后期绑定时,JVM会从方法区中的Latin方法表中取到Latin对象的直接地址,这就是真正执行结果为什么是Latin.play的原因,在解释方法表之前,我们先了解一下绑定的概念。

  将一个方法调用同一个方法主体关联起来被称作绑定,JAVA中分为前期绑定和后期绑定(动态绑定或运行时绑定),在程序执行之前进行绑定(由编译器和连接程序实现)叫做前期绑定,因为在编译阶段被调用方法的直接地址就已经存储在方法所属类的常量池中了,程序执行时直接调用,具体解释请看最后参考资料地址。后期绑定含义就是在程序运行时根据对象的类型进行绑定,想实现后期绑定,就必须具有某种机制,以便在运行时能判断对象的类型,从而找到对应的方法,简言之就是必须在对象中安置某种“类型信”,JAVA中除了static方法、final方法(private方法属于)之外,其他的方法都是后期绑定。后期绑定会涉及到JVM管理下的一个重要的数据结构——方法表,方法表以数组的形式记录当前类及其所有父类的可见方法字节码在内存中的直接地址。

  动态绑定具体的调用过程为:

    1.首先会找到被调用方法所属类的全限定名

    2.在此类的方法表中寻找被调用方法,如果找到,会将方法表中此方法的索引项记录到常量池中(这个过程叫常量池解析),如果没有,编译失败。

    3.根据具体实例化的对象找到方法区中此对象的方法表,再找到方法表中的被调用方法,最后通过直接地址找到字节码所在的内存空间。

  最后说明,域和静态方法都是不具有多态性的,任何的域访问操作都将由编译器解析,因此不是多态的。静态方法是跟类,而并非单个对象相关联的。对动态绑定还有不明白的请看资料链接,个人感觉分析的很到位

  参考资料:http://hxraid.iteye.com/blog/428891

 

深入理解JAVA多态原理的更多相关文章

  1. 【转】深入理解Java多态原理

    之前一直知道多态是什么东西,平时敲代码也经常用到多态,但一直没有真正了解多态底层的运行机制到底是怎么样的,这两天才研究明白点,特地写下来,跟各位同学一起进步,同时也希望各位大神指导和指正. 多态的概念 ...

  2. 深入理解java多态没有烤山药的存在,java就不香了吗?

    目录 1. 从吃烤山药重新认识多态 2. 多态前提条件[重点] 3. 多态的体现 4. 多态动态绑定与静态绑定 5. 多态特性的虚方法(virtual) 7. 向上转型 8. 向下转型 9. 向上向下 ...

  3. 深入理解Java多态机制

    从字节码层面来看,Java中的所有方法调用,最终无外乎转换为如下几条调用指令. invokestatic: 调用静态方法. invokespecial: 调用实例构造器<init>方法,私 ...

  4. 理解Java多态

    多态又称Polymophism,poly意思为多,polymophism即多种形态的意思.一种类型引用因为指向不同的子类,表现出不同的形态,使用不同的方法. 什么是多态 多态建议我们编码时使用comm ...

  5. 深入理解JAVA虚拟机原理之Dalvik虚拟机(三)

    更多Android高级架构进阶视频学习请点击:https://space.bilibili.com/474380680 本文是Android虚拟机系列文章的第三篇,专门介绍Andorid系统上曾经使用 ...

  6. 深入理解Java 注解原理

    *注解的用途 注解(Annotation)是JDK1.5引入的新特性,包含在java.lang.annotation包中,它是附加在代码中的一些元信息,将一个类的外部信息与内部成员联系起来,在编 译. ...

  7. 并发编程之美,带你深入理解java多线程原理

    1.什么是多线程? 多线程是为了使得多个线程并行的工作以完成多项任务,以提高系统的效率.线程是在同一时间需要完成多项任务的时候被实现的. 2.了解多线程 了解多线程之前我们先搞清楚几个重要的概念! 如 ...

  8. 深入理解JAVA虚拟机原理之内存分配策略(二)

    更多Android高级架构进阶视频学习请点击:https://space.bilibili.com/474380680 1.对象优先在Eden分配 大多情况,对象在新生代Eden区分配.当Eden区没 ...

  9. 深入理解JAVA虚拟机原理之垃圾回收器机制(一)

    更多Android高级架构进阶视频学习请点击:https://space.bilibili.com/474380680 对于程序计数器.虚拟机栈.本地方法栈这三个部分而言,其生命周期与相关线程有关,随 ...

随机推荐

  1. 向Git证明自己的身份,Git别名配置

    一.向Git证明自己的身份 在安装完Git后,第一步就是向Git说明自己的身份,通过如下两个命令证明: git config --global user.name "myusername&q ...

  2. 路径和 二叉树 leecode

    题目不难,很快ac,纯粹靠手感.https://oj.leetcode.com/problems/sum-root-to-leaf-numbers/ /** * Definition for bina ...

  3. ASP.NET MVC- VIEW Creating Custom HTML Helpers Part 2

    The goal of this tutorial is to demonstrate how you can create custom HTML Helpers     that you can ...

  4. Mina学习之IoSession

    Session(会话)是Mina的核心部分:每当一个clinent连接到server时,都会创建一个新的session,并且保存在内存中知道该链接断开. session 是用来存储一些关于连接信息,加 ...

  5. CentOS源码安装搭建LNMP全过程(包括nginx,mysql,php,svn)【转】

    转自:http://blog.csdn.net/yanzi1225627/article/details/49123659 服务器环境为:CentOS6.5 64位 目标:搭建LNMP(Linux + ...

  6. Activiti5.16.4数据库表结构

    一.ACTIVITI 数据库E-R图(5.16.4) Activiti 5.16.4 总共有24张表,增加act_evt_log(事件日志),以及增加了对SasS的支持. 在流程定义.运行实例和历史的 ...

  7. Linux模式设计系列( 内核与应用关联思考)

    http://blog.chinaunix.net/uid/20608849/cid-25333-list-2.html

  8. Linux下查看系统配置

    CPU 1. lscpu:显示cpu架构信息 [xxx@localhost ~]$ lscpu Architecture: x86_64 CPU op-mode(s): -bit, -bit Byte ...

  9. java 中能否使用 动态加载的类(Class.forName) 来做类型转换?

    今天同事提出了一个问题: 将对象a 转化为类型b,b 的classpath 是在配置文件中配置的,需要在运行中使用Class.forName 动态load进来,因为之前从来没有想过类似的问题,所以懵掉 ...

  10. linux中的网络通信指令 分类: 学习笔记 linux ubuntu 2015-07-06 16:02 134人阅读 评论(0) 收藏

    1.write write命令通信是一对一的通信,即两个人之间的通信,如上图. 效果图 用法:write <用户名> 2.wall wall指令可将信息发送给每位同意接收公众信息的终端机用 ...