A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 李白衣 中级黑马   /  2014-2-23 09:47  /  2835 人查看  /  23 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

class A
{
        public A()
        {
                foo();
        }

        public void foo()
        {
                System.out.println("A:foo()");
        }
}

class B extends A
{
        public B()
        {
        }
        public void foo()
        {
                System.out.println("B:foo()");
        }
}

public class Polymorphism
{

        public static void main(String[] args)
        {
                B b = new B();
        }

}

其打印输出的结果是 B:foo(),我想问下为什么是这样???

另外,我查找过C++里面的多态性,类似的程序,但是其输出结果是不一样的,理由如下:
在12.7.3条中有明确的规定。这是一种特例,在这种情况下,即在构造子类时调用父类的构造函数,而父类的构造函数中又调用了虚成员函数,这个虚成员函数即使被子类重写,也不允许发生多态的行为。即,这时必须要调用父类的虚函数,而不子类重写后的虚函数。


Java中是允许在构造函数中发生多态的。我也想过这之间的区别:因为Java是允许在定义数据成员的时候赋值的,C++却不允许,查找资料说是没有分配内存空间,这是不是由于它们的内存模型的区别导致的???


评分

参与人数 1技术分 +1 收起 理由
何伟超 + 1

查看全部评分

23 个回复

倒序浏览
C++不懂。但在Java中,确实是这样的。
因为创建的是子类B对象,B的构造方法默认会调用父类的无参构造super(),从而调用foo()方法,而B已经覆写了A的foo()方法,所以调用B的foo()方法。

评分

参与人数 1技术分 +1 收起 理由
何伟超 + 1

查看全部评分

回复 使用道具 举报
子类在对象初始化时,要先访问一下父类中的构造函数。
如果要访问父类中指定的构造函数,可以通过手动定义super语句的方式来指定.
虽然类的构造函数默认第一行有一条隐式的语句 super();super():会访问父类中空参数的构造函数
在对子类对象进行初始化时,父类的构造函数也会运行,但未用super手动指定,故输出的结果B:foo()
不知道对不对,纯属个人想法,本人也是初学者

评分

参与人数 1技术分 +1 收起 理由
何伟超 + 1

查看全部评分

回复 使用道具 举报
成员函数在多态调用时,编译看左边,运行时看右边。
这种方式在开发的时经常用到的,因为可以覆盖父类中的方法。

创建子类对象在调用的时候,函数的第一行会有一行默认的super();函数,他会调用父类的构造函数,而子类又重写了foo()方法,所以会执行子类中的foo()方法。

评分

参与人数 1技术分 +1 收起 理由
何伟超 + 1

查看全部评分

回复 使用道具 举报
明显类A中foo()方法的内容被覆盖了!

重写(覆盖):
当子类出现和父类一模一样的函数时,
当子类对象调用该函数,会运行子类函数的内容。
注意:
1.子类覆盖父类,必须保证子类权限大于等于父类权限,才可以覆盖,否则编译失败。
2.静态只能覆盖静态。

评分

参与人数 1技术分 +1 收起 理由
何伟超 + 1

查看全部评分

回复 使用道具 举报
我要的幸福呢 发表于 2014-2-23 10:40
C++不懂。但在Java中,确实是这样的。
因为创建的是子类B对象,B的构造方法默认会调用父类的无参构造super( ...

虽然B已经覆写了A的foo()方法,但是A实在构造函数调用的foo()方法啊,此时应该是A在调用,当前对象不应该是A么???那么就应该调用A的foo()方法啊
回复 使用道具 举报
sgs_gzy 发表于 2014-2-23 10:44
子类在对象初始化时,要先访问一下父类中的构造函数。
如果要访问父类中指定的构造函数,可以通过手动定义s ...

手动指定了super(),输出结果也是一样的啊
回复 使用道具 举报
张继鲁 发表于 2014-2-23 10:45
成员函数在多态调用时,编译看左边,运行时看右边。
这种方式在开发的时经常用到的,因为可以覆盖父类中的 ...

如果我将A的构造函数改成这样,
public A()
{
        this.foo();
}
那么在创建B对象的时候,这个this指针指向的是谁呢???
多态性是根据引用的实际指向对象来判断的,按照程序输出的结果,this是指向B对象咯???
回复 使用道具 举报
李白衣 发表于 2014-2-23 11:12
如果我将A的构造函数改成这样,
public A()
{

子类内存区里有一个this指针,指向了这个内存区里包括的父类实例区,当把子类对象付给一个父类引用时,是把子类内存区里面的父类实例区域的引用给了父类。
回复 使用道具 举报
本帖最后由 疲劳的小马 于 2014-2-23 20:41 编辑

这个贴是个好贴!以前从没遇到过这方面问题,视屏中也没学到关于这方面的,就是在构造函数中调用虚函数。本例中我实际验证过,不管主函数是 B b = new B();还是A a=new B();结果都是 B:foo()。所以只能理解为既定事实:java中子类在初始化时,如果父类的构造函数调用到了子类复写后的虚函数方法,那么初始化结果就是子类的方法。不存在C++里面的特例。

评分

参与人数 1技术分 +1 收起 理由
何伟超 + 1

查看全部评分

回复 使用道具 举报
开始的时候不太懂,就用一种比较笨的方法,在每一行代码下面都加一句
System.out.println(“x”);x=a,b,c,d。。。然后就一目了然了。
不过你说的这个问题都没有考虑过。

评分

参与人数 1技术分 +1 收起 理由
zzkang0206 + 1

查看全部评分

回复 使用道具 举报
你这个是继承的一种,继承时,子类B继承了A的函数即方法foo(),并且覆盖了这个方法。当new B()对象时,会调用B的无参构造方法,B的无参构造方法会默认调用A的无参构造方法,注意这里,A类无参构造方法里调用了foo()方法,但是你B类中重写覆盖了这个方法,所以打印出来的是B类的foo方法,运行时看具体所属对象!

评分

参与人数 1技术分 +1 收起 理由
zzkang0206 + 1

查看全部评分

回复 使用道具 举报
何伟超 发表于 2014-2-23 16:54
开始的时候不太懂,就用一种比较笨的方法,在每一行代码下面都加一句
System.out.println(“x”);x=a,b, ...

是呀,要不要把这题发帖重新问下呢?关于子父类构造函数调用虚函数的问题。那个版主大人,你是准备报多少期的啊?我现在感觉自己进度好慢,到现在才学到基础视屏12天,30期肯定是不行了,31期是三月多少号开班呀?
回复 使用道具 举报
疲劳的小马 发表于 2014-2-23 17:09
是呀,要不要把这题发帖重新问下呢?关于子父类构造函数调用虚函数的问题。那个版主大人,你是准备报多少 ...

我本来想进30的,但是刚刚提交基础测试,明天面试最后一天了。所以只能等了。31期市3月25号,加油吧,哥们,我们一起努力。
回复 使用道具 举报
李白衣 发表于 2014-2-23 11:04
虽然B已经覆写了A的foo()方法,但是A实在构造函数调用的foo()方法啊,此时应该是A在调用,当前对象不应该 ...

A并没有创建,可以想象成把A中的代码挪到了B中,调用的就是B中的方法,我是这么理解的
回复 使用道具 举报
疲劳的小马 发表于 2014-2-23 16:22
这个贴是个好贴!以前从没遇到过这方面问题,视屏中也没学到关于这方面的,就是在构造函数中调用虚函数。本 ...
  1. package itheima.blog;

  2. class A
  3. {
  4.         public String str = "hello";
  5.        
  6.         public A()
  7.         {
  8.                 this.foo();
  9.                 System.out.println(this.str);
  10.         }

  11.         public void foo()
  12.         {
  13.                 System.out.println("A:foo()");
  14.         }
  15. }

  16. class B extends A
  17. {
  18.         public B()
  19.         {
  20.                 str = null;
  21.         }
  22.         public void foo()
  23.         {
  24.                 System.out.println("B:foo()");
  25.         }
  26. }

  27. public class Polymorphism
  28. {

  29.         public static void main(String[] args)
  30.         {
  31.                 B b = new B();
  32.         }

  33. }
复制代码


看着果然有种不明觉厉的感觉啊!但是,
我觉得你说的 虚函数下面的代码都不执行!! 这句话不对。之前str之所以为空,是因为父类没有定义时初始化,子类继承后,其值就是默认为空。我又改了代码,输出就有值啦。
回复 使用道具 举报
徐青松 发表于 2014-2-23 17:08
你这个是继承的一种,继承时,子类B继承了A的函数即方法foo(),并且覆盖了这个方法。当new B()对象时,会 ...

其实这个问题的核心是,当我在A的构造函数里面写了这样的代码的时候
Public A
{
this.foo();
System.out.println(this.str);//str是一个A的成员变量
}
你觉得这两个this的指向分别是什么???

评分

参与人数 1技术分 +1 收起 理由
何伟超 + 1

查看全部评分

回复 使用道具 举报
何伟超 发表于 2014-2-23 17:24
我本来想进30的,但是刚刚提交基础测试,明天面试最后一天了。所以只能等了。31期市3月25号,加油吧,哥 ...

我也本来是想进30的,没想到明天居然是最后一天面试,我的技术分怎么办啊????看来只有等下一期了。家里人还一直催着我找工作呢,希望能坚持下去啊
回复 使用道具 举报
李白衣 发表于 2014-2-23 17:45
其实这个问题的核心是,当我在A的构造函数里面写了这样的代码的时候
Public A
{

this代表的是当前类对象的引用,你这里是A类对象的引用。当你在B类中写时,代表的就是B类中对象的引用。因为调用方法和属性有两种方式:一种是通过类名直接调用,这种情况下要求调用的方法或属性是静态的;另一种则是通过类去new一个对象去调用,这里就是普通方法和属性。比如:
class A {
    int x = 1;
    class B {
        int x = 2;
        void func() {
            int x = 3;
//这里我们要访问A的x怎么去访问呢?A的x是普通变量,必须用A的对象去调用,所以有A.this.x
这个this代表的就是A类对象,同理,B.this.x这个this代表的就是B类对象,this.x这里是在B类的func方法中,所以this还是代表的是B类对象,B.this.x==this.x。
            System.out.println("A的X为:"+A.this.x+"  B的X为:"+B.this.x+"  func的X为:"+this.x);
        }
    }
通过上面可以很清楚的认识到this代表的就是类对象,具体情况具体分析。
回复 使用道具 举报
子类覆盖了父类的foo方法。
1、子类继承父类,在被实例化时会自动调用父类的构造方法。
2、发现父类中有和子类同名、同型的foo。
3、将foo覆盖,打印子类syso内容。

评分

参与人数 1技术分 +1 收起 理由
何伟超 + 1

查看全部评分

回复 使用道具 举报
12下一页
您需要登录后才可以回帖 登录 | 加入黑马