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

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

代码如下,结果如下,我的问题是,子类中构造函数中,隐式 super();调用了父类的构造函数,父类中有个 speak()的函数,虽然子类把父类该函数给重写了,但是super调用的是父类的构造函数,不是应该调用父类的 speak() 吗?本人新手,基础较弱,请指教
public class Son extends Parent
{
        public static void main(String[] args)
        {
                new Son();
        }
        public void speak()
        {
                System.out.println("子类的i变量:"+this.i);
        }
}        
class Parent
{
        int i = 0;
        Parent()
        {
                this.i++;
                speak();
        }
       
        public void speak()
        {
                System.out.println("父类的i变量:"+this.i);
        }



}

该贴已经同步到 张帅的微博

16 个回复

倒序浏览
其实是调用的父类的speak方法,但是因为子类中也有speak方法,所以覆写了.最终运行的则是子类对象的speak方法.

评分

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

查看全部评分

回复 使用道具 举报
张帅 黑马帝 2011-12-20 10:15:45
藤椅
应国炎 发表于 2011-12-20 10:12
其实是调用的父类的speak方法,但是因为子类中也有speak方法,所以覆写了.最终运行的则是子类对象的speak方法 ...

但是,按我的理解,speak() 函数是写在,父类的构造函数中的,并且是在父类构造函数运行的时候运行,那时候跟子类没关系啊
回复 使用道具 举报
本帖最后由 monghuan 于 2011-12-20 10:22 编辑

执行语句:
new Son();
在调用Son()的构造函数前,会先自动调用父类的无参构造函数:super(),所以先执行以下语句:
this.i++; //1.最后i=1
speek(); //这边的speek()到底是调用父类还是子类?
注意:super不是一个对象的引用,只是一个指示编译器调用超类方法的关键字!不同于this的。所以在上面中,调用父类的无参构造函数:super()时,这边使用了super关键字,但实际上this仍然是子类对象的引用。

验证如下:
  1. class Son extends Parent
  2. {
  3.         public static void main(String[] args)
  4.         {
  5.                 new Son();
  6.         }
  7.         public void speek()
  8.         {
  9.                                       
  10.                 System.out.println("子类的i变量:"+this.i);
  11.         }
  12.         
  13. }        

  14. class Parent
  15. {
  16.         int i = 0;
  17.         Parent()
  18.         {
  19.                 this.i++;
  20.                 System.out.println("实际引用类型:"+this);
  21.                 speek();
  22.         }
  23.         
  24.         public void speek()
  25.         {                                      
  26.                 System.out.println("父类的i变量:"+this.i);
  27.         }
  28. }
复制代码
测试结果:
  1. 实际引用类型:Son@18a992f
  2. 子类的i变量:1
复制代码
【刚回答过,就直接复制过来了】

评分

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

查看全部评分

回复 使用道具 举报
张帅 黑马帝 2011-12-20 10:27:44
报纸
monghuan 发表于 2011-12-20 10:21
执行语句:
new Son();
在调用Son()的构造函数前,会先自动调用父类的无参构造函数:super(),所以先执行 ...

这句话不太理解
super不是一个对象的引用,只是一个指示编译器调用超类方法的关键字!不同于this的。所以在上面中,调用父类的无参构造函数:super()时,这边使用了super关键字,但实际上this仍然是子类对象的引用。
回复 使用道具 举报
张帅 发表于 2011-12-20 10:15
但是,按我的理解,speak() 函数是写在,父类的构造函数中的,并且是在父类构造函数运行的时候运行,那时 ...

new son();就是创建匿名子类对象,怎么会和子类没关系呢
回复 使用道具 举报
刘基军 黑马帝 2011-12-20 10:44:42
7#
张帅 发表于 2011-12-20 10:27
这句话不太理解

恩,现在已经明确:问题在“super”关键字身上,
【Java核心技术卷一中文第八版,145页(应该是这页),注释(原话)】
有些人认为super与this引用是类似的概念,实际上,这样比较并不恰当。这是因为super不是一个对象的引用,不能将super赋给另一个对象变量,它只是一个指示编译器调用超类方法的特有关键字。
[我是这么理解的,呵呵,]
回复 使用道具 举报
刘博 黑马帝 2011-12-20 10:47:55
8#
继承了父类的方法,你调用的话是先找子类的,如果子类没有才会去父类的找

评分

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

查看全部评分

回复 使用道具 举报
张帅 黑马帝 2011-12-20 10:56:03
9#
孤独的人 发表于 2011-12-20 10:47
继承了父类的方法,你调用的话是先找子类的,如果子类没有才会去父类的找

但是构造方法是不可以继承的, 该 speak() 函数在 父类的 构造函数中,子类根本不知道有这个 函数,他怎么会从自己 子类中寻找呢?
回复 使用道具 举报
我们可以这样理解 : 当你new一个子类对象时,它会调用父类的构造方法,我们可人认为调用的对象是子类在调用(Son.speak()),如果你没重写这个方法,它就直接去调用父类的方法。
回复 使用道具 举报
刘博 黑马帝 2011-12-20 11:04:08
11#
张帅 发表于 2011-12-20 10:56
但是构造方法是不可以继承的, 该 speak() 函数在 父类的 构造函数中,子类根本不知道有这个 函数,他怎 ...

你已经有了void关键字不是构造函数
回复 使用道具 举报
张帅 黑马帝 2011-12-20 12:04:27
12#
还是不理解,请大家帮帮我,谢谢了{:soso_e181:}
回复 使用道具 举报
舒远 黑马帝 2011-12-20 12:22:44
13#
你要明确一点,创建子类的过程是new Son(),java在创建对象之前会先找Son类的父类就是Parent类,调用子类构造器的时候会先调用父类的同参数列表的构造器。这是隐式调用实际上和super()作用一样。super()调用是显示调用。在调用父类构造函数的时候执行了speek方法。因为子类重写了speek方法。在父类构造器中调用被子类重写的方法时,此时如果是创建子类的对象,程序上下文环境中的this指向的就是正在创建的子类对象。那么调用的就是子类的speek方法。
不知道这样讲你能否明白?

评分

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

查看全部评分

回复 使用道具 举报
曾运 黑马帝 2011-12-20 13:14:48
14#
本帖最后由 曾运 于 2011-12-20 13:17 编辑

代码的分析如下:
  1. class Son extends Parent
  2. {
  3.         public static void main(String[] args)
  4.         {
  5.                 new Son();
  6.         }
  7.         public void speek()
  8.         {
  9.                                       
  10.                 System.out.println("子类的i变量:"+this.i);
  11.         }

  12.                 Son()
  13.                 {
  14.                         super();//子类实例化过程中会先用父类无参构造函数,Son类从Parent类继承的i会执行+1,再根据就近原则,调用自己重写的speek方法
  15.                         super.speek();//因为子类重写父类的speek方法,要使用父类的speek方法,要通过关键字super
  16.                 }
  17.         
  18. }        

  19. class Parent
  20. {
  21.         int i = 0;
  22.         Parent()
  23.         {
  24.                 this.i++;
  25.                 speek();
  26.         }
  27.         
  28.         public void speek()
  29.         {                                      
  30.                 System.out.println("父类的i变量:"+this.i);
  31.         }
  32. }
复制代码
输出结果:

子类的i变量:1
父类的i变量:1

点评

对我也有帮助  发表于 2011-12-20 13:46

评分

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

查看全部评分

回复 使用道具 举报
张帅 黑马帝 2011-12-20 13:16:13
15#
舒远 发表于 2011-12-20 12:22
你要明确一点,创建子类的过程是new Son(),java在创建对象之前会先找Son类的父类就是Parent类,调用子类构 ...

对,我的疑问就在这里,在父类的构造函数里,给变量 i 赋值,应该是给父类的 变量 i 赋值吧?
回复 使用道具 举报
舒远 黑马帝 2011-12-20 13:23:04
16#
张帅 发表于 2011-12-20 13:16
对,我的疑问就在这里,在父类的构造函数里,给变量 i 赋值,应该是给父类的 变量 i 赋值吧? ...

如果没有子类继承该父类,那就不存在new子类实例这么一说。那你可以认为是在父类中对成员变量i赋值。但是如果有子类,并且调用子类构造函数了,由于java对象创建时初始化具有需要先调用父类构造器的这个特点。程序在运行时的this指向就是子类了。和编译时的指向不是一回事。所以在这个例子中给变量i赋值实际上是在给子类中从父类继承来的那个i赋值。如果你调用的是new Parent(),那么代码中的i赋值语句就肯定是给父类中的赋值。因为就是他自己在调用自己的构造器嘛。
所以说到底的话:要弄明白编译时的this指向和运行时的this指向到底是怎么回事!
通常不会在父类构造函数中调用会被子类重写的方法。有可能引发错误,有时候这个错误是很危险的。

评分

参与人数 1技术分 +2 收起 理由
admin + 2 赞一个!

查看全部评分

回复 使用道具 举报
张帅 黑马帝 2011-12-20 13:41:42
17#
舒远 发表于 2011-12-20 13:23
如果没有子类继承该父类,那就不存在new子类实例这么一说。那你可以认为是在父类中对成员变量i赋值。但是 ...

原来如此,我终于明白了,原来是这样的,看来我看视频的时候没看懂,非常感谢 舒远 ,帮助教会我东西,再次感谢
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马