如果在构造函数中使用 super 调用重写方法会发生什么

2024-05-11

有两个班级Super1 and Sub1

超1级

public class Super1 {
    Super1 (){
        this.printThree();
    }

    public void printThree(){
        System.out.println("Print Three");
    }    
}

亚1级

public class Sub1 extends Super1 {
    Sub1 (){
        super.printThree();
    }

    int three=(int) Math.PI;

    public void printThree(){
        System.out.println(three);
    }

    public static void main(String ...a){
         new Sub1().printThree();
    }
}

当我调用该方法时printThree班级的Sub1我预计输出是:

打印三
3

Because Sub1构造函数调用super.printThree();.

但我实际上得到

0
打印三
3

我知道 0 是默认值int但它是怎么发生的呢?


您会看到三件事的影响:

  1. 默认超级构造函数调用,以及

  2. 与超级调用相关的实例初始值设定项,以及

  3. 重写方法如何工作

Your Sub1构造函数是really this:

Sub1(){
    super();               // <== Default super() call, inserted by the compiler
    three=(int) Math.PI;   // <== Instance initializers are really inserted
                           // into constructors by the compiler
    super.printThree();
}

(令人惊讶,我知道,但这是真的。使用javap -c YourClass看看。 :-) )

The reason看起来超类必须有机会初始化它的对象部分before子类可以初始化its物体的一部分。所以你会得到这种交织的效果。

鉴于这就是Sub1 really看起来像,让我们来看看:

  1. JVM 创建实例并将所有实例字段设置为其默认值(所有位均关闭)。所以此时,three字段存在,并且具有值0.

  2. JVM 调用Sub1.

  3. Sub1立即致电super() (Super1), 哪个...

    1. ...打电话printThree. Since printThree被覆盖,即使对它的调用是在代码中Super1,这是被覆盖方法(其中的一个Sub1)被调用。这是Java 实现多态性的一部分。自从three的实例初始化程序尚未运行,three包含0,这就是输出。

    2. Super1返回。

  4. Back in Sub1,实例初始化代码three插入的编译器(实际上是重新定位的)运行并给出three一个新的价值。

  5. Sub1 calls printThree. Since three的实例初始值设定项代码现已运行,printThree prints 3.

关于将此实例初始值设定项代码移至构造函数中,您可能想知道:如果我有多个构造函数怎么办?代码被移入哪一个?答案是编译器重复代码到每个构造函数中。 (你可以在javap -c,也是。)(如果您有一个非常复杂的实例初始值设定项,如果编译器有效地将其转换为方法,我不会感到惊讶,但我还没有看过。)

如果你做了一些非常顽皮的事情并在实例初始化期间调用一个方法,那就更清楚了:(实时复制 http://ideone.com/y2uGWY)

class Super
{
    public static void main (String[] args) {
        new Sub();
    }

    Super() {
        System.out.println("Super constructor");
        this.printThree();
    }

    protected void printThree() {
        System.out.println("Super's printThree");
    }
}
class Sub extends Super
{
    int three = this.initThree();

    Sub() {
        this.printThree();
    }

    private int initThree() {
        System.out.println("Sub's initThree");
        return 3;
    }

    protected void printThree() {
        System.out.println("Sub's printThree: " + this.three);
    }
}

Output:



Super constructor
Sub's printThree: 0
Sub's initThree
Sub's printThree: 3
  

请注意“Sub's initThree”在该序列中出现的位置。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如果在构造函数中使用 super 调用重写方法会发生什么 的相关文章

随机推荐

  • 错误:NVIDIA-SMI 失败,因为无法与 NVIDIA 驱动程序通信

    NVIDIA SMI 抛出此错误 NVIDIA SMI 失败 因为无法与 NVIDIA 通信 司机 确保安装了最新的 NVIDIA 驱动程序并且 跑步 我清除了 NVIDIA 并按照提到的步骤重新安装了它here https askubun
  • 如何使用jsPDF设置图像以适合页面宽度?

    有什么办法可以解决这个问题吗 我尝试以毫米为单位设置宽度和高度 如何将其设置为全角 您可以获取 PDF 文档的宽度和高度 如下所示 var doc new jsPDF p mm a4 var width doc internal pageS
  • 如何在VB.NET中画一条线

    我正在尝试用 VB NET 画一条简单的线 我的代码如下 但是当我运行代码时 只显示表单 没有线 我在这里做错了什么 Public Class Form1 Dim pen As System Drawing Graphics Private
  • 准备编程竞赛的缩写和函数[关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心 help reopen questi
  • 是否可以动态导入模块?

    我有很多角度组件的导入 看起来我可以编写一个函数来简化导入 我只是不知道怎么做 但这应该很简单 进口样本 import DashboardComponent from app components dashboard dashboard c
  • 在浏览器中打开的 .mhtml 文件中填写输入

    我想对 mhtml 文件运行 e2e 测试 即填写表格 在 mhtml 文件上查看和提取数据效果非常好 但我无法填写任何内容input字段 既不是手动也不是通过木偶操作者 你可以用这个试试 mhtml 文件 https gist githu
  • 如何使用javascript通过类名更改html元素的值

    这是我用来更改 html 元素值的代码 a class classname href Vtech com This text to be chnage a 如何在页面加载瞬间更改此文本 看来你需要添加DOMContentLoaded或者把你
  • 在 Dart 中重写哈希码的好方法是什么?

    我发现自己想要覆盖对象的 hashcode 和 并且我想知道是否有最佳实践来实现依赖于多个属性的 hashcode 并且似乎有一些特定于 Dart 的注意事项 最简单的答案是将所有属性的哈希值异或在一起 这可能还不错 Dart Up 和 R
  • Android 改造参数化@Headers

    我正在使用 OAuth 每次发出请求时都需要将 OAuth 令牌放入标头中 我看到 Header注释 但是有没有办法让它参数化 以便我可以在运行时传入 这是概念 Header Authorization OAuth var api vers
  • 如何捕获生成器抛出的异常并恢复迭代?

    我有一个生成器 它将值的集合传递给方法并生成结果 调用的方法可能会返回异常 发生这种情况时 我希望异常转到调用生成器来处理异常的代码 然后继续循环生成器 为了说明这一点 下面是一个生成器的示例 它将产生1 抛出一个 Exception 然后
  • method_存在于父类php中

    我正在尝试使用 php 函数 method exists 但我需要检查该方法是否存在于对象的父类中 so class Parent public function myFunction class Child extends Parent
  • 如何在as3中不询问的情况下写入外部文件

    我有这个代码 var fileRef FileReference new FileReference fileRef save ciao coso lingua txt 在现有的 lingua txt 文件上写入 该脚本有效 但每次他保存时
  • 使用 https 的 Java Jersey RESTful Web 服务

    我是 Java EE 的新手 正在开发一个 RESTful API 其中每个 API 调用用户都会发送编码的凭据 我的问题是如何通过默认的 http 实现 https 协议并确保我的连接安全 我正在使用 Jersey Restful Web
  • php 中接口的用途是什么?

    如果我在 PHP 中定义一个接口 以及一个创建该接口实例的工厂类 有什么方法可以强制客户端代码仅使用该接口而不使用底层具体类 根据我的理解 客户也可以实际使用底层类中的任何公共函数 字段 这是一个例子
  • HTML 中按钮内的图标

    我需要在 HTML 中将小图标放在按钮内 例如 我需要在我的网站上有 facebook 按钮 在按钮内首先是 F 图标 然后是 facebook 怎么做
  • Linux命令列出所有可用命令和别名

    是否有一个 Linux 命令可以列出该终端会话的所有可用命令和别名 就好像您输入 a 并按下 Tab 键一样 但针对的是字母表中的每个字母 或者运行 别名 但也返回命令 为什么 我想运行以下命令并查看命令是否可用 ListAllComman
  • 2D 中的大量旋转

    我正在尝试使用 Bevy 0 3 并且我可以轻松使用内置转换Camera2dComponents default 这是自上而下的二维 问题在于尝试将玩家的旋转与鼠标同步 for event in evreader iter cursor m
  • Spring-data-cassandra:创建名称为“sessionFactory”的 bean 时出错,并且无法解析对 bean“cassandraTemplate”的引用

    我有一个 springboot 应用程序 在其中连接到 cassandra DB 我的 pom xml parent gt
  • 在 TFS 2012 中使用持续集成进行自动部署

    我已经为 WCF 项目设置了持续集成 并希望使用 MSBuild 参数自动将应用程序部署到远程服务器 但它没有部署 运行新的构建时 所有测试都会通过并且所有项目都会构建 但网站尚未部署 另外 我没有从构建中收到任何错误 表明出现了任何问题
  • 如果在构造函数中使用 super 调用重写方法会发生什么

    有两个班级Super1 and Sub1 超1级 public class Super1 Super1 this printThree public void printThree System out println Print Thre