java-当我在构造函数中调用方法时会发生什么?
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。
您正在构建一个RoundGLyph
实例。 RoundGLyph
的构造函数调用超类的构造函数 - Glyph
- 它调用draw()
方法。由于RoundGLyph
覆盖Glyph
的draw()
方法,Glyph
构造函数调用RoundGLyph
draw()
方法,该方法打印的值为radius
。
然而,由于它被调用之前完全初始化的RoundGLyph
实例(RoundGLyph
构造的身体还没有被尚未执行,甚至radius = 1
初始化尚未执行),在radius
变量仍持有默认值为0
。由于Java语言的这种行为,建议不要在构造函数中调用非final方法(因为它们可以被覆盖)。
在这种情况下,正在调用超级构造函数,即正在调用字形构造函数。现在正在发生的棘手的事情是对RoundGlyph中被重写的draw()方法的调用,因此Glyph会调用RoundGlyph中的重写版本,该版本会打印半径变量,但是又一个奇怪的观察结果是打印0因为子构造函数语句直到现在还没有被执行,所以由于它是一个原语,所以打印默认值0。如果它是某个对象,那么null将被打印。希望澄清它。
方法将被正常调用。这次由这个指向的对象是不完美的,但是这个指针在那里,所以不会有异常,但是建议不要这样做,因为在一个不完美的对象上调用实例方法是危险的。
感谢您的回答。这是否意味着编译器将RoundGlyph作为第一个参数提供给draw()?正如我所知道的,当我调用t.f()时,用t类型的T,编译器会将它变成T.f(t)。 – Lucas
@Lucas,你的例子中的'draw'方法被称为'this',就像实例方法一样。由于它是从'RoundGlyph'构造函数调用的,'this'是指一个正在构建的'RoundGlyph'实例。正如我们所知,该对象是存在的,因为构造函数正在执行,如果该对象不存在,则无法执行该对象。 “在调用draw()时没有创建RoundGlyph”是错误的。实例在构造函数执行之前由'new'创建。 –