小A:“什麼是構造器?”
大B:“首先要注意的是Java的構造器並不是函數,所以他並不能被繼承,這在我們extends的時候寫子類的構造器時比較的常見,即使子類構造器參數和父類的完全一樣,我們也要寫super就是因為這個原因。構造器的修飾符比較的有限,僅僅隻有publicprivateprotected這三個,其他的例如任何修飾符都不能對其使用,也就是說構造器不允許被成名成抽象、同步、靜態等等訪問限製以外的形式。因為構造器不是函數,所以它是沒有返回值的,也不允許有返回值。但是這裏要說明一下,構造器中允許存在return語句,但是return什麼都不返回,如果你指定了返回值,雖然編譯器不會報出任何錯誤,但是JVM會認為他是一個與構造器同名的函數罷了,這樣就會出現一些莫名其妙的無法找到構造器的錯誤,這裏是要加倍注意的。”
小A:“在我們extends一個子類的時候經常會出現一些意想不到的問題,你能和我說說一些和構造器有關的嗎?”
大B:“首先說一下Java在構造實例時的順序(不討論裝載類的過程),構造的粗略過程如下1、分配對象空間,並將對象中成員初始化為0或者空,java不允許用戶操縱一個不定值的對象。2、執行屬性值的顯式初始化。3、執行構造器。4、將變量關聯到堆中的對象上。”
小A:“能介紹一下準備知識嗎?以備一會來詳細了解這個的流程。”
大B:“thissuper是你如果想用傳入當前構造器中的參數或者構造器中的數據調用其他構造器或者控製父類構造器時使用的,在一個構造器中你隻能使用this或者super之中的一個,而且調用的位置隻能在構造器的第一行,在子類中如果你希望調用父類的構造器來初始化父類的部分,那就用合適的參數來調用super,如果你用沒有參數的super來調用父類的構造器(同時也沒有使用this來調用其他構造器),父類缺省的構造器會被調用,如果父類沒有缺省的構造器,那編譯器就會報一個錯誤,注意這裏,我們經常在繼承父類的時候構造器中並不寫和父類有關的內容,此時如果父類沒有缺省構造器,就會出現編譯器添加的缺省構造器給你添麻煩的問題了哦!例如:Classbextendsa{publicb{}}就沒有任何有關父類構造器的信息,這時父類的缺省構造器就會被調用。”
舉個SL-275中的例子
publicManager(Stringdept){//這裏就沒有super,編譯器會自動地添加一個空參數的缺省super構造器,此時如果Employee類中沒有空參數的缺省構造器,那就會導致一個編譯錯誤。
大B:“你必須在構造器的第一行放置super或者this構造器,否則編譯器會自動地放一個空參數的super構造器的,其他的構造器也可以調用super或者this,調用成一個遞歸構造鏈,最後的結果是父類的構造器(可能有多級父類構造器)始終在子類的構造器之前執行,遞歸的調用父類構造器。在具體構造類實例的過程中,上邊過程的第二步和第三步是有一些變化的,這裏的順序是這樣的,分配了對象空間及對象成員初始化為默認值之後,構造器就遞歸的從繼承樹由根部向下調用,每個構造器的執行過程是這樣的:1、Bind構造器的參數。2、如果顯式的調用了this,那就遞歸調用this構造器然後跳到步驟5.3、遞歸調用顯式或者隱式的父類構造器,除了Object以外,因為它沒有父類。4、執行顯式的實例變量初始化(也就是上邊的流程中的第二步,調用返回以後執行,這個步驟相當於在父構造器執行後隱含執行的,看樣子像一個特殊處理)。5、執行構造器的其它部分。”
小A:“好像有點明白了。”
大B:“這裏的步驟很重要哦!從這個步驟中可以很明顯的發現這個實例初始化時的遞歸調用過程。”
(本章完)