Java 重写(Override)与重载(Overload)

重写(Override)

重写是子类对父类的允许访问的方法的实现过程进行重新编写, 返回值和形参都不能改变。即外壳不变,核心重写!

重写的好处在于子类可以根据需要,定义特定于自己的行为。 也就是说子类能够根据需要实现父类的方法。

重载(Overload)

重载(overloading) 是在一个类里面,方法名字相同,而参数不同。返回类型可以相同也可以不同。

每个重载的方法(或者构造函数)都必须有一个独一无二的参数类型列表。

方法的重写(Overriding)和重载(Overloading)是java多态性的不同表现,重写是父类与子类之间多态性的一种表现,重载可以理解成多态的具体表现形式。

  • (1)方法重载是一个类中定义了多个方法名相同,而他们的参数的数量不同或数量相同而类型和次序不同,则称为方法的重载(Overloading)。
  • (2)方法重写是在子类存在方法与父类的方法的名字相同,而且参数的个数与类型一样,返回值也一样的方法,就称为重写(Overriding)。
  • (3)方法重载是一个类的多态性表现,而方法重写是子类与父类的一种多态性表现。

——————————————————————————————————————————————————————————————————————

分派

JVM字节码的执行涉及到方法的调用,其中分派调用过程将会解释Java多态特性,

1. 静态分派

首先是一段重载代码:

public class StaticDispatch {

    static abstract class Human{

    }

    static class Man extends Human{

    }

    static class Woman extends Human{

    }

    public void sayHello(Human guy){
System.out.println("Hello, guy!");
} public void sayHello(Man guy){
System.out.println("Hello, gentleman!");
} public void sayHello(Woman guy){
System.out.println("Hello, lady!");
} public static void main(String[] args) {
Human man = new Man();
Human woman = new Woman();
StaticDispatch sr = new StaticDispatch();
sr.sayHello(man);
sr.sayHello(woman);
}
}

与重载有关,代码的执行结果为:

但为什么会选择执行参数类型为Human的重载呢?

Human man = new Man();

在上面那段代码中,Human称为变量的静态类型(static type),Man称为变量的实际类型(actual type), 静态类型和实际类型在程序中都会发生变化,区别是静态类型的变化仅仅发生在使用期,变量本身的静态类型不会发生改变,并且静态类型是编译期可

知的。而实际类型变化的结果只有运行期才可以确定,编译期并不知道变量的实际类型是什么。

例如

//实际类型变化举例
Human man = new Man();
man = new Woman(); //静态类型变化举例
sr.sayHello((Man)man);
sr.sayHello((Woman)woman);

在之前的代码中,方法的接收者已经确定为sr的情况下,使用哪一个重载的版本取决于传入参数的数据类型。但编译器在重载的时候是以参数的静态类型而不是实际类型作为判断依据的。

因此结果就是执行sayHello(Human)作为调用的目标。

2. 动态分派

首先是一段重写代码:

public class Dynamicdispatch {

    static abstract class Human{
protected abstract void sayHello();
}
static class Man extends Human{ @Override
protected void sayHello() {
// TODO Auto-generated method stub
System.out.println("man say hello!");
} }
static class Woman extends Human{ @Override
protected void sayHello() {
// TODO Auto-generated method stub
System.out.println("woman say hello!");
} } public static void main(String[] args) {
Human man = new Man();
Human woman = new Woman();
man.sayHello();
woman.sayHello();
man = new Woman();
man.sayHello();
}
}

代码执行的结果:

现在的问题是虚拟机如何知道要调用什么方法?

可以javap -verbose来反编译输出的信息。

16和20句把创建好的两个对象的引用压到栈顶,这两个对象是将要执行sayHello()方法的所有者,为接收者; 17和21是方法调用指令,这两个指令都指向了#22号,就是Human.sayHello(),但是最终执行的目标方法却是不相同的。

这与invokevirtual指令的运行时解析有关:

  1. 找到操作数栈顶的第一个元素所指向的对象的实际类型;
  2. 如果在该类型中找到与常量中的描述符和简单名称都相同的方法,进行权限访问,通过则返回这个方法的引用;
  3. 否则对该类型的父类进行第二步的搜索和验证;
  4. 如果始终找不到就跑出异常。

由于invokevirtual指令执行的第一步就是在运行期确定接收者的实际类型,所以两次指令都将符号引用解析到了不同的直接引用上去了。这就是重写的本质。

3. 单分派与多分派

静态多分派,动态单分派(到目前为止)

方法的接收者和方法的参数统称为方法的宗量。

静态分派过程中,选择目标方法的依据:静态类型的选择和方法参数的选择

动态分派过程中,选择目标方法的依据:静态类型,因为在动态执行时,编译期已经决定目标方法的签名(参数),所以不会关心传过来的参数。

从JVM字节码执行看重载和重写的更多相关文章

  1. JVM总结(五):JVM字节码执行引擎

    JVM字节码执行引擎 运行时栈帧结构 局部变量表 操作数栈 动态连接 方法返回地址 附加信息 方法调用 解析 分派 –“重载”和“重写”的实现 静态分派 动态分派 单分派和多分派 JVM动态分派的实现 ...

  2. 一夜搞懂 | JVM 字节码执行引擎

    前言 本文已经收录到我的 Github 个人博客,欢迎大佬们光临寒舍: 我的 GIthub 博客 学习导图 一.为什么要学习字节码执行引擎? 代码编译的结果从本地机器码转变为字节码,是存储格式发展的一 ...

  3. JVM 字节码执行实例分析

    前言 最近在看<Java 虚拟机规范>和<深入理解JVM虚拟机>,对于字节码的执行有了进一步的了解.字节码就像是汇编语言,是 JVM 的指令集.下面我们先对 JVM 执行引擎做 ...

  4. 从jvm字节码指令看i=i++和i=++i的区别

    1. 场景的产生 先来看下下面代码展示的两个场景 @Testvoid testIPP() { int i = 0; for (int j = 0; j < 10; j++) { i = i++; ...

  5. 深入理解JVM—字节码执行引擎

    原文地址:http://yhjhappy234.blog.163.com/blog/static/3163283220122204355694/ 前面我们不止一次的提到,Java是一种跨平台的语言,为 ...

  6. JVM字节码执行引擎和动态绑定原理

    1.执行引擎 所有Java虚拟机的执行引擎都是一致的: 输入的是字节码文件,处理过程就是解析过程,最后输出执行结果. 在整个过程不同的数据在不同的结构中进行处理. 2.栈帧 jvm进行方法调用和方法执 ...

  7. jvm 字节码执行 (一)方法调用

    “虚拟机”是一个相对于“物理机”的概念,这两种机器都有代码执行能力,其区别是物理机的执行引擎是直接建立在处理器.硬件.指令集和操作系统层面上,而虚拟机的执行引擎是 由自己实现的,因此可以自行制定指令集 ...

  8. JVM字节码执行引擎

    一.概述 在不同的虚拟机实现里面,执行引擎在执行Java代码的时候可能会有解释执行(通过解释器执行)和编译器执行(通过即时编译器产生本地代码执行)两种选择,所有的Java虚拟机的执行引擎都是一致的:输 ...

  9. jvm 字节码执行 (二)动态类型支持与基于栈的字节码解释执行

    动态类型语言 动态类型语言的关键特征是它的类型检查的主体过程是在运行期而不是编译期. 举例子解释“类型检查”,例如代码: obj.println("hello world"); 假 ...

随机推荐

  1. 实现快餐配送页面jq

    <!DOCTYPE html><html> <head> <meta charset="utf-8"> <title>快 ...

  2. tf.train.ExponentialMovingAverage

    这个函数可以参考吴恩达deeplearning.ai中的指数加权平均. 和指数加权平均不一样的是,tensorflow中提供的这个函数,能够让decay_rate随着step的变化而变化.(在训练初期 ...

  3. SQL-Oracle游标

    游标提供了一种从集合性质的结果集中提供出单条记录的手段.初始时指向首记录. 游标的种类 静态游标.REF游标 静态游标:能够理解为一个数据快照,打开游标后的结果集是数据库表中数据的备份,数据不会对表的 ...

  4. 八皇后問題 (C語言递归實現 回溯法)

    八皇后问题是一个以国际象棋为背景的问题:怎样可以在 8×8 的国际象棋棋盘上放置八个皇后,使得不论什么一个皇后都无法直接吃掉其它的皇后?为了达到此目的.任两个皇后都不能处于同一条横行.纵行或斜线上.現 ...

  5. Power Designer如何批量改动数据类型

    最近做项目的时候须要将OOM转换为PDM.在OOM中转换为PDM时,全部string的类型的属性都默认变为varchar(254),这可不是我们须要的类型,那么.如此多的类.如此多的属性.难道一个一个 ...

  6. Android中使用ContentProvider进行跨进程方法调用

    原文同一时候发表在我的博客 点我进入还能看到很多其它 需求背景 近期接到这样一个需求,须要和别的 App 进行联动交互,比方下载器 App 和桌面 App 进行联动.桌面的 App 能直接显示下载器 ...

  7. Bootstrap全局CSS样式之排版

    Bootstrap能全然友好的支持html5的文本元素,这里不再赘述,详细可參考我还有一篇文章<html的文本元素总结>,这里主要针对Bootstrap封装好的CSS文本样式做一下汇总. ...

  8. day01_使用Android Studio创建第一个Android项目

    使用Android Studio开发Android项目如此简单 watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize ...

  9. IT运维如何防止陷入“中年油腻”和频繁被动地打“遭遇战”?

    欢迎大家前往腾讯云社区,获取更多腾讯海量技术实践干货哦~ 作者:陈峻近期,我拜访了一家文化传播公司的 IT 运维总监 Tim,他向我讲述了他的团队是如何像当年玩<大航海时代>那样将 IT ...

  10. Hibernate(或其它ORM)里的inverse用法详解,内容摘自Java web轻量级开发面试教程

    本文来是从 java web轻量级开发面试教程从摘录的. Inverse的英文含义是反转,在Hibernate中用来决定是由哪方来维护两个业务实体类之间的关联关系,具体而言,就是由哪方去设置这个被外键 ...