图解Java多态内存分配以及多态中成员方法的特点

 
 
Person worker = new Worker(); 子类实例对象地址赋值给父类类型引用变量。多态的体现。
多态中成员方法的特点分析:
【子类有,父类没有】编译失败!!!
worker.startWork(); 为什么编译不通过呢?提示:找不到符号。
因为引用变量worker是Person类型,在Person类的方法表中查找方法startWork(),找得到吗?找不到,更别提常量池解析了。编译失败。

【子类有,父类有,重写,非静态】调用子类!!!
worker.say(); 子类重写父类方法,被重写的方法在子类跟父类的方法表中索引相同。
调用的时候,在父类类型的方法表中查找say方法的索引,然后把索引存到PolDemo类的常量表中(常量池解析,就是用Person类方法表中的索引项来代替常量池中的符号引用)。
因为索引相同,直接拿常量表中say方法的索引去子类方法表中调用say()方法。 所以,此时调用的是被子类重写的方法。见图中的内存分配。

【子类有,父类有,静态】调用当前引用类型变量类型中的方法。
因为静态是属于类的,由实例共享,所以只看当前引用变量所属的类中的静态方法。

多态中(父类引用指向子类对象)成员方法(非静态)有以下特点:
编译期根据引用类型变量所属的类型方法表中是否有调用的方法,没有编译失败。
运行期根据在堆中创建对象的实际类型找到对应的方法表,从中确定具体的方法在内存中的位置。

堆中实例对象:子类包含父类,子类对父类说:你的就是我的,我的还是我的。

多态中成员变量的特点分析:
无论编译期还是运行期,都只参考引用类型变量所属的类中是否有对象的成员变量。

小的总结:
再来看这条语句:Person worker = new Worker(): 多态,父类引用指向子类对象。
跟这句代码的作用是一样的,Worker w = new Worker(); Person worker = w; 就是子类的引用传给父类类型的引用。向上转型,都指向一个实例对象(子类)。
1:为什么可以将子类实例对象的引用传给父类类型引用呢? 
答:多态的体现,鸽子是鸟类,鹦鹉是鸟类,喜鹊是鸟类,它们都是鸟类,这就是鸟类的多种表现形态(多态),
它们有鸟类的基本特征与行为,并且还有自己特有的行为,那就会把鸟类的基本特征与行为继承过来给自己。extends关键字声明了他们的关系。
程序中这句话 鸟类 xx鸟 = new 鸽子();就创建了一个鸟类的引用,它是鸽子。
类的概念是抽象的,所以它就仅仅是个引用,只有引用到实例对象,它才真正实现了自己。

2:父与子的关系会怎样呢?
由于Worker类继承自Person类,所以会先加载Person类并初始化成员变量在Worker类实例对象中。这就是子类继承过来的成员变量。
如果子类中定义了与父类相同的成员变量,变量不会存在重写,子类实例对象中会有两份相同名称的实例变量,调用时,父类的会被隐藏。
如果想调用父类被隐藏的成员变量,那就要使用super关键字。
同样,子类会继承父类的成员方法作为自己的成员方法,如果子类定义了与父类相同的成员方法(重写),多态中会调用子类自己的成员方法。

3:多态,又有什么好处呢?跟这样写(Worker worker = new Worker();)有什么区别,不一样继承父类的属性方法吗?
首先明确: Worker worker = new Worker();这样写仅仅是继承关系。不存在多态特性。
Person worker = new Worker(); 这样写就展示了多态的关系,鸽子是鸟类的一种表现形态。
有啥好处?一句话概括:提高了程序的扩展性,表现在什么地方呢?比如:
现在有个工厂,能解析鸟类的语言,鸽子是鸟类吧?Ok,那建一个工厂,让鸽子说。
public static void doWork(Dove dove) {
String sound = dove.say(); // ... 拿到鸽子说的话
}
鹦鹉是鸟类吧?Ok,那建一个工厂,让鹦鹉说。
public static void doWork(Parrot parrot) {
String sound = parrot.say(); // ... 拿到鹦鹉说的话
}
如果还有一千个鸟类要说话,那我岂不得建一千座工厂?。。。累不累?那既然都是鸟类,我建一个鸟类的工厂不就行了嘛?
public static void doWork(Bird bird) {
String sound = bird.say(); // ... 拿到xx鸟说的话。。。
}
这时候,无论你什么鸟进来,我都让你说话,而且说得都是你自己的话,因为你继承我并重写了你的功能。
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Worker w = (Worker)worker; // 向下转型。目的,为了调用子类非继承父类、自己特有的方法。
因为多态有个弊端,只能使用父类的引用访问父类的成员。所以向下转型是为了访问子类自己的成员。
首先,worker引用指向的实例对象本来就是子类类型的。所以赋值给子类类型引用变量非常可以。
然后现在用子类类型的引用就可以访问自己的成员方法了啦啦啦。

 
 

(转载)图解Java多态内存分配以及多态中成员方法的特点的更多相关文章

  1. 图解Java继承内存分配

    图解Java继承内存分配   继承的基本概念: (1)Java不支持多继承,也就是说子类至多只能有一个父类. (2)子类继承了其父类中不是私有的成员变量和成员方法,作为自己的成员变量和方法. (3)子 ...

  2. Java 对象内存分配与回收

    JVM内存区域模型: * 程序计数器,内存区域极小,是当前线程的字节码执行行号指示器: * 虚拟机栈.本地方法栈,即平时所说的“栈”,是虚拟机用来执行方法(包括Java.非Java方法)时,使用的临时 ...

  3. java继承内存分配

    java继承内存分配 继承的基本概念: * Java不支持多继承,也就是说子类至多只能有一个父类. * 子类继承了其父类中不是私有的成员变量和成员方法,作为自己的成员变量和方法. * 子类中定义的成员 ...

  4. JAVA虚拟机内存分配与回收机制

    Java虚拟机(Java Virtual Machine) 简称JVM Java虚拟机是一个想象中的机器,在实际的计算机上通过软件模拟来实现.Java虚拟机有自己想象中的硬件,如处理器.堆栈.寄存器等 ...

  5. java 继承内存分配

    今天,复习的是继承的内存分配.我们知道,Java中内存可以初略分为堆.栈.方法区. package sort; class Person{ public int age; public String  ...

  6. 深入理解java虚拟机---内存分配策略(十三)

    转载请注明原文地址:https://blog.csdn.net/initphp/article/details/30487407 Java内存分配策略 使用的ParNew+Serial Old收集器组 ...

  7. Java的内存分配

    java内存分配 A:栈 存储局部变量 B:堆 存储所有new出来的 C:方法区(方法区的内存中) 类加载时 方法信息保存在一块称为方法区的内存中, 并不随你创建对象而随对象保存于堆中; D:本地方法 ...

  8. 小白请教几个关于Java虚拟机内存分配策略的问题

    最近在看周志明所著的<深入理解Java虚拟机>,有几个问题不太明白,希望对虚拟机有研究的哥们儿帮我解答一下.先说一下我进行试验的环境: 操作系统:Mac OS X 10.11.6 EI C ...

  9. 理解java虚拟机内存分配堆,栈和方法区

    栈:存放局部变量 堆:存放new出来的对象 方法区:存放类的信息,static变量,常量池(字符串常量) 在堆中,可以说是堆的一部分   创建了一个student类,定义了name属性, id静态变量 ...

随机推荐

  1. bzoj4238 & loj2881 电压 二分图判定+dfs树

    题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=4238 https://loj.ac/problem/2881 题解 如果想要让每一条边都有电流 ...

  2. man clock

    CLOCK(3)   Linux程序员手册   CLOCK(3) 名称  时钟-确定处理器时间 简介  #include <time.h>    clock_t clock(void);  ...

  3. day04记

    useGeneratedKeys useGeneratedKeys这个只在insert语句中有效,正常情况下useGeneratedKeys默认为false 当useGeneratedKeys为tru ...

  4. JConsole和VisualVM远程访问JMX

    1.jvisualvm监控tomcat 修改tomcat的bin目录下的 catalina.sh文件,搜索JAVA_OPTS="",在引号中添加参数 JAVA_OPTS=" ...

  5. mysql分组排序加序号(不用存储过程,就简简单单sql语句哦)

    做前端好长时间了,好久没动sql了.在追一个喜欢的女孩,做测试的,有这么个需求求助与本屌丝,机会难得,开始折腾起来,配置mysql,建库,建表.... 一 建表 CREATE TABLE `my_te ...

  6. JS中的执行机制(setTimeout、setInterval、promise、宏任务、微任务)

    1.执行机制 JS 是单线程的,处理 JS 任务(程序)只能一个一个顺序执行,所以 JS 中就把任务分为了同步任务和异步任务.同步的进入主线程先执行,异步的进入Event Table并注册函数,当指定 ...

  7. CF D. Labyrinth 01BFS

    由于上下走不限制,所以按照贪心,我们应该尽可能走上下方向. 我们可以开一个双端队列,并认为每次提取队首的时候得到的是到达该点的最优策略.(这个一定是唯一的,因为不可能向右走几格,然后再退回去. ) 那 ...

  8. R 画散点图

    ggplot(data=df, aes(x=n, y=rt, group=kernel, shape=kernel, colour=kernel)) + geom_point(fill="w ...

  9. 项目开源-基于ASP.NET Core和EF Core的快速开发框架

    前言:作为一名95后的程序猿,已经写了一年多的代码了,为了提升自己的技术水平,所以决定尝试编写一个快速开发框架开源出来,一来提升自己的技术水平,二来助力.NET Core生态发展 写这个框架主要是为了 ...

  10. VMware 虚拟化编程(4) — VDDK 安装

    目录 目录 前文列表 VDDK 安装 VDDK 前文列表 VMware 虚拟化编程(1) - VMDK/VDDK/VixDiskLib/VADP 概念简析 VMware 虚拟化编程(2) - 虚拟磁盘 ...