黑马程序员技术交流社区

标题: 关于子类的实例化过程(父类构造方法调用子类里方法的..... [打印本页]

作者: 申俊伟    时间: 2012-10-2 14:53
标题: 关于子类的实例化过程(父类构造方法调用子类里方法的.....
本帖最后由 申俊伟 于 2012-10-2 21:56 编辑

public class Test {
    public static void main(String[] args) {
        B a = new B();

    }
}
class A {
    int a = 10;
    A() {
        print();           //此处是调用子类的还是父类的?
    }
    void print() {
        System.out.println(a);
    }
}

class B extends A {
    int a = 20;

    B() {
        print();
    }
    void print() {
        System.out.println(a);
    }
}
当父类的构造方法调用了父类的某个方法,而父类的这个方法又被子类覆盖,那么在实例化子类时要调用父类的构造方法,而父类的构造方法此时是调用子类的这个方法还是父类的?
在父类里不是应该调用父类的吗?为什么结果是0,20


作者: 古银平    时间: 2012-10-2 15:14
本帖最后由 古银平 于 2012-10-2 15:22 编辑

子类的所有的构造函数,默认都会访问父类中空参数的构造函数。
因为子类每一个构造函数内的第一行都有一句隐式super();

当父类中没有空参数的构造函数时,子类必须手动通过super语句形式来指定要访问父类中的构造函数。

当然:子类的构造函数第一行也可以手动指定this语句来访问本类中的构造函数。
子类中至少会有一个构造函数会访问父类中的构造函数
调用的是父类的

无标题.png (36.63 KB, 下载次数: 146)

无标题.png

作者: 何小红    时间: 2012-10-2 15:39
调用子类的,因为子类的方法已将父类的覆盖了。
class A {
  void fun1() {
    System.out.println(fun2());
  }
  int fun2() {
    return 123;
  }
}

class B extends A {
  int fun2() {                //复写父类A中的fun2()方法
    return 456;   
  }
  public static void main(String argv[]) {
    A a;
    B b = new B();       
  b.fun1();                //覆盖之后调用子类中被覆盖的方法,输出456
    a = b;                //父类引用指向子类对象
  a.fun1();                //多态 输出456
  }
}       

作者: 何小红    时间: 2012-10-2 15:40
这是另外一个例子,我们曾经做过的,和你的一样,贴上看下哈
输出结果为: 456
作者: 申俊伟    时间: 2012-10-2 17:12
古银平 发表于 2012-10-2 15:14
子类的所有的构造函数,默认都会访问父类中空参数的构造函数。
因为子类每一个构造函数内的第一行都有一句 ...

第四中,父类构造方法调用的是那个print()?子类的还是父类的?
作者: 申俊伟    时间: 2012-10-2 17:12
古银平 发表于 2012-10-2 15:14
子类的所有的构造函数,默认都会访问父类中空参数的构造函数。
因为子类每一个构造函数内的第一行都有一句 ...

第四中,父类构造方法调用的是那个print()?子类的还是父类的?
作者: 申俊伟    时间: 2012-10-2 17:24
何小红 发表于 2012-10-2 15:39
调用子类的,因为子类的方法已将父类的覆盖了。
class A {
  void fun1() {

父类可以调用子类的方法吗?
作者: 古银平    时间: 2012-10-2 17:27
申俊伟 发表于 2012-10-2 17:12
第四中,父类构造方法调用的是那个print()?子类的还是父类的?

print()前面忽略了的是this。原型为this.print(),现在应该知道调用那个了吧,this关键字是那个对象调用就代表那个对象,你创建的狮子类的对象,所以调用的是子类的print()。
作者: 何小红    时间: 2012-10-2 17:37
B a=new B();
你已把 a强转为了B类型,难道不是调用B类的print()?
你的子类B已经覆盖a的print(),又没有指定调用父类的方法,肯定是调用子类B的方法啊

作者: 何小红    时间: 2012-10-2 17:41
对了,毕老师在面向对象时有讲过的例子,毕姥爷和毕老师的,那个能够说明,仔细看看哈

作者: 黑马-王燚    时间: 2012-10-2 17:50

B a=new B();   这明明是 子类类型 创建子类对象
程序执行完这句话之后
首先执行 B类的  构造代码块(在这个程序中)
B()
{
              //super();    这里隐式的调用了这样的一句话
}
所以1.先去调用父类的构造方法,然后发现 父类调用了它自己的 print()方法,  但是这个时候 父类并没有创建确确实实的对象   所以a采用的值是默认int类型的 值为0,所以打印的时候为0
2.然后 完了之后 再去子类中调用 它自己的 print()方法,  由于子类有new B()这句话,说明在堆内存中分配了空间 而且 还对其子类的成员变量赋值  a=20,所以打印出来的时候 就是20

作者: 黑马-王燚    时间: 2012-10-2 18:43
补充更正一下  ,初始化的 过程(在这个题当中)
1.a = 10
2.父类构造函数
3.a = 20
4.子类构造函数
父类构造函数调用的是子类的print()
子类print打印子类变量此时还没初始化赋值,默认为int类型值 为0

作者: 胡斌    时间: 2012-10-2 19:27

public class lok {
    public static void main(String[] args) {
        B a = new B();//创建对象要注意程序执行的过程,当创建对象时首先通过super()调用父类构造函数初始化,给你的a值赋值为0,然后调用输出为0,接下来调用你的B类构造函数输出20.

    }
}
class A {
    int a = 10;
    A() {
        print();           //此处是调用子类的还是父类的?
    }
    void print() {
        System.out.println(a);
    }
}

class B extends A {
    int a = 20;//成员变量与超类变量同名,父类变量被隐藏,由于父类a被隐藏,所以在第一步输出0,而子类的a为20.

    B() {
        print();
    }
    void print() {//子类重写了超类方法,则子类对象调用这个方法时,调用子类方法,如果子类继承了超类的方法(为重写),则调用父类方法。
        System.out.println(a);
    }
}
作者: 会盟天下英豪    时间: 2015-10-22 22:18
本帖最后由 会盟天下英豪 于 2015-10-22 22:55 编辑

1.调用子类的print().因为类B继承类A,且类B出现和类A同样的函数,当实例化类B后,调用print()方法,会运行B类函数的内容,即重写,这也是多态在函数中的一种体现形式。2.成员初始化过程,即所有变量在使用前都能得到恰当的初始化。
(1)B a=new B(),在B类对象初始化时,A类的构造函数也会运行,因为B类构造函数默认第一行有一条隐式的语句super(),super()会访问A类的空参数的构造函数。
(2)A类的构造函数调用print(),由于B类已经重写该方法,则调用B类的print(),当创建B类对象是,该对象包含了A类的子对象,即对象a中会有两个数据成员a,一个为A类的,一个为B类的,但主函数并没有实例化A,因为java会对类的每个基本类型数据成员保证都会有一个初始值,而A类数据成员为int型,所以打印结果为0.
(3)当调用完A类构造函数,接下来调用B类构造函数,因为一实例化类B,且显示的初始化了类B对象的数据成员,即int a=20,所以打印结果为20.






欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2