2017-04-23 40 views
1
class Glyph { 
    void draw() { 
     print("Glyph.draw()"); 
    } 

    Glyph() { 
     print("Glyph() before draw()"); 
     draw(); 
     print("Glyph() after draw()"); 
    } 

} 
class RoundGlyph extends Glyph{ 
    private int radius = 1; 
    RoundGlyph(int r){ 
     radius = r; 
     print("RoundGLyph.draw(), radius = " + radius); 
    } 
    void draw(){ 
     print("radius:" + radius); 
    } 
    public static void main(String[] args){ 
     new RoundGlyph(5); 

    } 

} 

//Glyph() before draw() 
radius:0 
Glyph() after draw() 
RoundGLyph.draw(), radius = 5 

上面的代碼。java-當我在構造函數中調用方法時會發生什麼?

由於draw()不是靜態的,所以必須給它一個隱式參數(this)。在這種情況下,在Glyph的構造函數中調用draw(),所以我想知道這個「隱式參數」是什麼。 正如我所知道的,當我調用t.f()時,用t類型的T,編譯器會將它變成T.f(t)。

結果表明,在我看來,它是一個作爲此參數提供的RoundGlyph。但這怎麼可能?顯然,在調用draw()時不會創建RoundGlyph。

回答

6

您正在構建一個RoundGLyph實例。 RoundGLyph的構造函數調用超類的構造函數 - Glyph - 它調用draw()方法。由於RoundGLyph覆蓋Glyphdraw()方法,Glyph構造函數調用RoundGLyphdraw()方法,該方法打印的值爲radius

然而,由於它被調用之前完全初始化的RoundGLyph實例(RoundGLyph構造的身體還沒有被尚未執行,甚至radius = 1初始化尚未執行),在radius變量仍持有默認值爲0。由於Java語言的這種行爲,建議不要在構造函數中調用非final方法(因爲它們可以被覆蓋)。

+0

感謝您的回答。這是否意味着編譯器將RoundGlyph作爲第一個參數提供給draw()?正如我所知道的,當我調用t.f()時,用t類型的T,編譯器會將它變成T.f(t)。 – Lucas

+1

@Lucas,你的例子中的'draw'方法被稱爲'this',就像實例方法一樣。由於它是從'RoundGlyph'構造函數調用的,'this'是指一個正在構建的'RoundGlyph'實例。正如我們所知,該對象是存在的,因爲構造函數正在執行,如果該對象不存在,則無法執行該對象。 「在調用draw()時沒有創建RoundGlyph」是錯誤的。實例在構造函數執行之前由'new'創建。 –

0

在這種情況下,正在調用超級構造函數,即正在調用字形構造函數。現在正在發生的棘手的事情是對RoundGlyph中被重寫的draw()方法的調用,因此Glyph會調用RoundGlyph中的重寫版本,該版本會打印半徑變量,但是又一個奇怪的觀察結果是打印0因爲子構造函數語句直到現在還沒有被執行,所以由於它是一個原語,所以打印默認值0。如果它是某個對象,那麼null將被打印。希望澄清它。

1

方法將被正常調用。這次由這個指向的對象是不完美的,但是這個指針在那裏,所以不會有異常,但是建議不要這樣做,因爲在一個不完美的對象上調用實例方法是危險的。

相關問題