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之類的涉及類型檢查的操作時,類的元數據里的結構信息就派上用場了。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM