zoukankan      html  css  js  c++  java
  • Java 类的构造器中this()和super()的困惑

      关于构造器中super的使用,书本上这样写:

      “super是指向父类的引用,如果构造方法没有显示地调用父类的构造方法,那么编译器会自动为它加上一个默认的super()方法调用。如果父类由没有默认的无参构造方法,编译器就会报错,super()语句必须是构造方法的第一个子句。”

      首先我要纠正一个我刚刚才发现的印象流错误,我之前一直以为,无论有没有自定义构造器,编译器为自动为每个类生成一个“方法体为空的无参构造方法”。但上面那段话,指出了,一个类是有可能没有默认的无参构造方法的。于是我往回翻了书,书上的原文为:

      “类可以不定义构造方法,这时编译器会为类隐含声明一个方法体为空的无参构造方法。但当类有明确声明的构造方法时,编译器就不会自动生成无参构造方法了。”

      说明一旦你自定义了构造方法,编译器就不会帮你自动生成方法体为空的无参构造方法。我之前的印象流是错的。

      

      我们再来看书本上关于this的描述:

      “this表示一个对象的引用,它指向正在执行方法的对象。特别的,在构造方法中通过this关键字调用其他构造方法时,必须放在第一行,否则编译器会报错。且在构造方法中,只能通过this调用一次其他构造方法。”

      综合上面的描述,会有一个疑问,能否在同一个构造器中同时显示地使用this和super?

      (这个问题在知乎上有讨论,详情请转义阵地。在这里我直接搬运过来了)

      假定这里讨论的构造器都没有显式的super()调用,则:

    • 有显式this()调用的构造器就会抑制掉该构造器里隐式的super()调用;
    • 没有显式this()调用的构造器则会得到隐式的super()调用。

      this()调用会借助别的重载版本的构造器来做部分初始化,而一连串this()最后来到的构造器必然是没有显式this()调用的,这里就会有显式或隐式的super()调用。举个例子:

    public class Base {
      private int x;
      public Base() {
        // super(); // 这里开头没有this()调用,编译器会合成隐式的super()调用
        this.x = 42;
      }
    }
    
    public class Derived extends Base {
      private char c;
      private Object o;
    
      public Derived() {
        this('a'); // 这里开头有this()调用,编译器不会合成隐式的super()调用
      }
    
      public Derived(char c) {
        this(c, null); // 同上,不会合成super()调用
      }
    
      public Derived(char c, Object o) {
        // super(); // 这里开头没有this()调用,编译器会合成隐式的super()调用
        this.c = c;
        this.o = 0;
      }
    }
    
    作者:RednaxelaFX
    链接:https://www.zhihu.com/question/41810504/answer/117132716
    来源:知乎
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

       在这个例子里,如果有 new Derived(),则一连串的构造器调用会是:

    Derived()                 // 最初的new
      Derived(char)           //   经过this()
        Derived(char, Object) //     经过this()
          Base()              //       经过super()
            Object()          //         来到Object()

      这就是我想说的,一连串this()的最后一个必然不再会在开头有this()调用,而这个开头没有this()调用的构造器就会得到编译器给隐式合成的super()调用。

      这里没有直接回答“能不能在同一构造器同时显示调用super()和this()”的问题,但考虑下,如果能的话,最终会有两次super()调用,也就是说我们没有理由,在同一个构造器中同时调用super()和this()。

      那么强行在同一个构造器中同时调用super()和this()会发生什么呢?

      结果是编译器禁止这样做,无论把哪个放在构造器的第一行,都会出现以下其中一个错误:

    Error:(6, 13) java: call to this must be first statement in constructor
    Error:(6, 14) java: call to super must be first statement in constructor

      那么super()的调用究竟完成了什么工作?难道它创建了一个父类对象吗?

      首先,super是指向“父类”的引用,不是像“this”一样指向一个对象。

      由于一个子类的实例会包含其所有基类所声明的字段(所有噢,包括私有,这些字段也需要初始化),外加自己声明的字段。而super()是父类封装对自己声明的字段进行初始化的手段。

      所以,并没有创建一个父类对象,因为仅仅有那些父类声明的字段构不成一个完整的实例。

       Java对象是这样组织的(概念上):

       一个Derived实例就是一个Derived实例。它的this()会负责初始化自己所声明的字段的部分,而它通过(递归-)调用super()来初始化基类祖先们所声明的字段的部分。

      每个Java实例上会记录足够类型信息来表明自己具体是哪个类的实例,这里就是Derived类的实例。
      然后每个类的元数据会包括结构信息,例如说自己的superClass是谁。这里Derived类会知道自己的superClass是Base,而Base知道自己的superClass是Object。
      当我们需要执行instanceof、checkcast、arraystore之类的涉及类型检查的操作时,类的元数据里的结构信息就派上用场了。
  • 相关阅读:
    sqlserver更新数据表结构增加新字段时,和它相关联的视图出现错列现象
    form表单中的Input使用disabled不能提交的解决方法
    MVC4升级到MVC5的问题,安全透明方法“WebMatrix.WebData.PreApplicationStartCode.Start()”尝试访问安全关键方法“System.Web.WebPages.Razor.WebPageRazorHost.AddGlobalImport(System.String)”失败
    快速建立一个手机网站
    NoSQLMongoDB选择
    基于HTML5手机技术方案(如Phonegap)的调试方案
    最后的绝唱Symbian 最新的IDE开发环境搭建(Updated on 20110307)
    由NodeJS浅谈无敌的前端开发工程师
    物联网(1)手机NFC识别方案平台
    大话网站从Hello World到高并发网站
  • 原文地址:https://www.cnblogs.com/bigbigbigo/p/8574517.html
Copyright © 2011-2022 走看看