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

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© dev 中级黑马   /  2012-6-28 17:53  /  3079 人查看  /  6 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

本帖最后由 翁游龙 于 2012-6-29 16:54 编辑

    看书的时候了解到,在访问权限允许的情况下,子类可以调用父类的方法,
但父类不能调用子类的方法,因为父类根本无从知道它将被哪个子类继承,
它的子类将会增加怎样的方法。(这些我都可以理解)
    但有一种特殊情况,当子类方法重写了父类方法之后,父类表面上只是调用属于
自己的方法,可实际上是调用子类的方法。关于以下代码有点不明白的地方:

class Animal{
        //desc实例变量保存对象toString方法的返回值
        private String desc;
        public Animal(){
                //调用getDesc()方法初始化desc实例变量
                this.desc = getDesc();
        }
        public String getDesc(){
                return "Animal";
        }
        public String toString(){
                return desc;
        }
}

public class Wolf extends Animal{
        private String name;
        private double weight;

        public Wolf(String name, double weight){
                this.name = name;
                this.weight = weight;
        }
        //重写父类的getDesc()方法
        @Override
        public String getDesc(){
                return "Wolf[name=" + name + ",weight=" + weight + "]";
        }
        public static void main(String[] args){
                System.out.println(new Wolf("灰太狼",32.3));
        }
}

运行结果为:
Wolf[name=null,weight=0.0]

问题:为什么运行结果name=null,weight=0.0,程序中不是在构造方法中为这两个
属性赋值了吗,结果为什么不是name=灰太狼,weight=32.2?这里不是很明白,请
高手指点下。谢谢!



6 个回复

倒序浏览
new Wolf("灰太狼",32.3)---->进入子类的构造方法-->调用父类构造方法public Animal()-->父类的构造方法调用getDesc()方法--->非静态的方法是对象的方法,这个getDesc方法是子类对象的   此时子类的构造方法连super()都没运行外,下面的 this.name = name;和this.weight = weight;还没运行到,
对象的成员都有默认值,所以就是那个打印结果。
回复 使用道具 举报
我也不明白,但是代码改成这样后就可以了
  1. class Animal
  2. {
  3.         // desc实例变量保存对象toString方法的返回值
  4.         private String desc;

  5.         public Animal()
  6.         {
  7.                 // 调用getDesc()方法初始化desc实例变量
  8.                 this.desc = getDesc();
  9.         }

  10.         public String getDesc()
  11.         {
  12.                 return "Animal";
  13.         }

  14.         public String toString()
  15.         {
  16.                 return desc;
  17.         }
  18. }

  19. public class Wolf extends Animal
  20. {
  21.         private String name;
  22.         private double weight;

  23.         public Wolf(String name, double weight)
  24.         {
  25.                 this.name = name;
  26.                 this.weight = weight;
  27.         }

  28.         // 重写父类的getDesc()方法
  29.         @Override
  30.         public String getDesc()
  31.         {
  32.                 return "Wolf[name=" + name + ",weight=" + weight + "]";
  33.         }

  34.         public static void main(String[] args)
  35.         {
  36.                 System.out.println(new Wolf("灰太狼", 32.3).getDesc());
  37.         }
  38. }
复制代码
回复 使用道具 举报
哥们这句话
new Wolf("灰太狼",32.3)//意思是调用了Wolf类的构造函数,
在下边的这段代码中..
public class Wolf extends Animal{
        private String name;
        private double weight;

        public Wolf(String name, double weight){
                this.name = name;
                this.weight = weight;
        }
        //重写父类的getDesc()方法
        @Override
        public String getDesc(){
                return "Wolf[name=" + name + ",weight=" + weight + "]";
        }
        public static void main(String[] args){
                System.out.println(new Wolf("灰太狼",32.3));
        }
}
是按照顺序执行的,进入入口后new了个Wolf类对象,进入类中,先是属性的默认初始化,构造代码块初始化..
重点在这: 你后边还有个return语句,它返回的值是默认的初始化值,并且记录下来...
所以在你输出时是默认的初始化值.
.
也就是Wolf[name=null,weight=0.0]
回复 使用道具 举报
这里new Wolf("灰太狼",32.3),先执行父类构造函数:
public Animal(){
                 //调用getDesc()方法初始化desc实例变量
                 this.desc = getDesc();
         }
构造函数里执行 this.desc = getDesc();的时候因为子类重写了getDesc();,
所以执行子类的getDesc();
此时子类的构造函数还没有执行,子类的name和weight成员变量都是默认值,
所以getDesc();返回Wolf[name=null,weight=0.0]
所以desc就是Wolf[name=null,weight=0.0]
然后再执行子类的构造函数这个时候才会初始化name,
但是desc这个字符串是不会变了。
所以最后输出的是Wolf[name=null,weight=0.0]
回复 使用道具 举报
class Animal{
        //desc实例变量保存对象toString方法的返回值
        private String desc;
        public Animal(){
                //调用getDesc()方法初始化desc实例变量
                this.desc = getDesc();
        }
        public String getDesc(){
                return "Animal";
        }
        public String toString(){
                return desc;
        }
}

public class Wolf extends Animal{
        private String name;
        private double weight;

        public Wolf(String name, double weight){
                this.name = name;
                this.weight = weight;
        }
        //重写父类的getDesc()方法
        @Override
        public String getDesc(){
                return "Wolf[name=" + name + ",weight=" + weight + "]";
        }
        public static void main(String[] args){
                System.out.println(new Wolf("灰太狼",32.3));
        }
}
运行的原理是这样的....
1.你用new Wolf("灰太狼",32.3));这句话实例化了Wolf但是因为Wolf extends 了Animal 所以在这里首先执行Animal 的构造方法。。进入第2步
2.     public Animal(){
                //调用getDesc()方法初始化desc实例变量
                this.desc = getDesc();
        }
利用getDesc()给desc赋值,然后会调用tostring()输出,因为子类重写了父类的getdesc()方法,但是此时子类的name属性和weight属性都还没有初始化,所以这个时候调用tostring输出的只能是null
回复 使用道具 举报
dev 中级黑马 2012-6-29 16:54:04
7#
车风波 发表于 2012-6-28 18:10
这里new Wolf("灰太狼",32.3),先执行父类构造函数:
public Animal(){
                 //调用getDesc() ...

你解释的很好,我明白了,哈哈。谢谢了!
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马