这里想问一个java函数调用顺序的问题public class Base {
public Base(){
this.sayHello();
System.out.println("Base");
}
public void sayHello(){
System.out.println("sayHello in base");
}
}public class Derived extends Base {
public Derived (){
this.sayHello();
System.out.println("Derived");
}
public void sayHello(){
System.out.println("sayHello in Derived");
}
}public class Test { /**
* @param args
*/
public static void main(String[] args) {
Derived d = new Derived();
}}
这里生成一个子类的对象,生成子类对象的时候,在子类执行构造函数时调用父类的构造函数。
父类构造函数中有this.sayHello();方法。这里执行的是子类的sayHello方法。
问题就在这里,为什么是执行子类的sayHello方法呢?如果是c++的话执行的是父类的sayHello方法。
因为java里面的函数都是virtual的,所以sayHello方法在子类里被复写了,所以执行了子类的sayHello方法。
但是在执行父类的构造函数的时候,子类应该还没有生成啊,他怎么能执行子类的sayHello方法呢?
如果说子类已经生成了,为什么没有执行子类的构造函数呢?
非常不解,望高手指点!
public Base(){
this.sayHello();
System.out.println("Base");
}
public void sayHello(){
System.out.println("sayHello in base");
}
}public class Derived extends Base {
public Derived (){
this.sayHello();
System.out.println("Derived");
}
public void sayHello(){
System.out.println("sayHello in Derived");
}
}public class Test { /**
* @param args
*/
public static void main(String[] args) {
Derived d = new Derived();
}}
这里生成一个子类的对象,生成子类对象的时候,在子类执行构造函数时调用父类的构造函数。
父类构造函数中有this.sayHello();方法。这里执行的是子类的sayHello方法。
问题就在这里,为什么是执行子类的sayHello方法呢?如果是c++的话执行的是父类的sayHello方法。
因为java里面的函数都是virtual的,所以sayHello方法在子类里被复写了,所以执行了子类的sayHello方法。
但是在执行父类的构造函数的时候,子类应该还没有生成啊,他怎么能执行子类的sayHello方法呢?
如果说子类已经生成了,为什么没有执行子类的构造函数呢?
非常不解,望高手指点!
父类构造函数中有this.sayHello();方法。这里执行的是子类的sayHello方法。
问题就在这里,为什么是执行子类的sayHello方法呢?
//因为 : Derived d = new Derived(); 这里new出来的是Derived的对象,所以执行的是子类的sayHello方法但是在执行父类的构造函数的时候,子类应该还没有生成啊,他怎么能执行子类的sayHello方法呢? 这里是先调用父类的构造函数,再调用子类的构造函数,建议你用Debug调试一下。
建议基类里要调用的方法不要写成公有的或保护的, 以免出现这种情况
当你new Derived()的时候,先调用父类,因为子类override了父类的方法,所以得到如下结果:
sayHello in Derived
Base
sayHello in Derived
Derived
感觉大家还是没有解释到问题的关键。//因为 : Derived d = new Derived(); 这里new出来的是Derived的对象,所以执行的是子类的sayHello方法
但是sayHello方法是在父类的构造函数里调用的,子类都没有生成,怎么调用子类的方法了?这里是先调用父类的构造函数,再调用子类的构造函数,建议你用Debug调试一下。
对啊,就是因为是这样的顺序,所以在父类执行的时候怎么可能子类生成了呢?子类都没生成,怎么能调用子类的方法呢?
public static void main(String[] args) {
Sub s=new Sub();
}
}class Base
{
public Base()
{
this.sayHello();
System.out.println("Base");
}
public void sayHello()
{
System.out.println("sayHello in Base");
}
}class Sub extends Base
{
public Sub()
{
this.sayHello();
System.out.println("Sub");
}
public void sayHello()
{
System.out.println("sayHello in Sub");
}
}当你创建Sub实例的时候,执行Sub类的构造方法,因为这里没有显式的调用Sub类的构造方法,所以编译的时候会自动调用父类的无参构造方法,所以在执行this.sayHello();之前会先调用Base();可能疑惑的在这个地方,Base类里面是this.sayHello()阿,也就是调用本类的,那为什么会调用到子类上面去的.? 这是因为子类重写了父类的方法, this只是个隐式参数而已,代表的是当前对象. 然而你看你main方法里面当前对象是什么呢? 是new Sub();所以这里的this代表的是new Sub(),相当与是Base b=new Sub(); 因为重写所发生的多态,所以运行时会自动的去找Sub类的sayHello()方法.! 子类里面的方法就不用再多说了吧? 关键是this这个关键字的理解. 记住this只是代表当前对象而已..
debug有什么用呢?
debug的时候在父类的构造函数执行sayHello方法的时候进入到了子类的sayHello方法。
大家一般都会说是因为子类复写了父类的sayHello方法。
但是这时候子类都没有生成,又怎么能执行子类的方法呢?如果这时候子类已经有了,为什么没有执行子类的构造函数呢?
请大家认真阅读,别再误解,老说调试下就知道了,这不是调试的问题。
下面我把你的程序改一下.我再来说, 看注释public class Test {
public static void main(String[] args) {
Sub s=new Sub();
s.sayHello();
}
}class Base
{
public Base()
{
//this.sayHello();
//System.out.println("Base");
}
public void sayHello()
{
System.out.println("sayHello in Base");
}
//请看这个方法f(), 方法f调用当前对象的sayHello()对吧?而此时,因为有子类重写了父类,所以在编译期是无法得知这个sayHello()到底是哪个版本吧? 只有到了运行期,Sub s=new Sub(); 因为继承,所以s继承了方法f();那么这个this是当前对象的引用,也就是父类的引用,指向子类对象的实例 .. 所以在运行期 这个this就相当于是Base b=s;所以很自然的,这个运行的结果是子类版本的sayHello();
public void f()
{
this.sayHello();
}
}class Sub extends Base
{
public Sub()
{
//this.sayHello();
//System.out.println("Sub");
}
public void sayHello()
{
System.out.println("sayHello in Sub");
}
}
不知道各位明白没? 还是多态.. 好好想下吧
请看这个方法f(), 方法f调用当前对象的sayHello()对吧?而此时,因为有子类重写了父类,所以在编译期是无法得知这个sayHello()到底是哪个版本吧? 只有到了运行期,Sub s=new Sub(); 因为继承,所以s继承了方法f();那么这个this是当前对象的引用,也就是父类的引用,指向子类对象的实例 .. 所以在运行期 这个this就相当于是Base b=s;所以很自然的,这个运行的结果是子类版本的sayHello();