黑马程序员技术交流社区

标题: 子类覆盖父类 ~小问题 [打印本页]

作者: 杨贺阳    时间: 2012-7-10 23:21
标题: 子类覆盖父类 ~小问题
本帖最后由 杨贺阳 于 2012-7-11 01:05 编辑

问题一、子类覆盖父类的对象值之后,父类的值会改变吗??
    能不能用一个小代码说明一下。
问题二、 为什么下面这个代码,子类没有把父类覆盖,运行结果却是把4、5都打印出来了?
class  fu
{
        fu()
         {       int a=4;
                System.out.println(a);
        }
}

class zi extends fu
{
        zi()
        {      
                int a=5;
                System.out.println(a);
        }
}
class  name
{
        public static void main(String[] args)
        {
               
                zi x=new zi();
               
        }
}

作者: 田向向    时间: 2012-7-10 23:28
class zi extends fu
{
      super();
         zi()
         {      
                 int a=5;
                 System.out.println(a);
         }
}
因为子类继承父类,所以在子类第一行有一句隐形的super();所以打印子类的时候也把父类的4打印出来了。
具体的毕老师的视频里讲的都很清楚,,自己好好看看吧哥们
作者: 高原    时间: 2012-7-10 23:42
问题1:你问的是子类中有和父类同名的成员变量吧,“对象值”这叫法太不专业了……
如果父类和子类中有非私有同名成员变量,这情况不叫覆盖!而且父类引用只能访问自己定义的的成员变量,不能访问子类定义的同名成员变量
总结:方法(非静态)在多态调用时,编译看左边,运行看右边;成员变量和静态成员(静态方法和静态变量)在多态调用时,无论编译还是运行,都看左边。这里的左边右边值的是创建对象时 “=” 的左边和右边
至于写代码嘛,你自己应该有能力写的,自己写写试试,这样记忆才深刻
问题2:代码中是那两个方法是构造方法,创建子类对象并调用子类构造方法时,会默认调用父类的无参构造方法,当然会都打印了,这是个对象的初始化问题,这几天论坛里问的很多了,比如:http://bbs.itheima.com/forum.php?mod=viewthread&tid=18804
你也可以自己去找找相关的帖子,有些帖子总结的非常好。

作者: 尹善波    时间: 2012-7-10 23:44
class  fu
{
        fu()
         {       int a=4;
                System.out.println(a);//第三步
        }
}
class zi extends fu
{
        zi()
        {      
   //super();  第二步;;隐式的,对子类初始化时首先运行,访问父类
                int a=5;
                System.out.println(a);//第四步
        }
}
class  name
{
        public static void main(String[] args)
        {
               
                zi x=new zi();//第一步
     //对子类对象进行初始化时,父类的构造函数也会运行,这是因为,
                 //子类的构造函数的默认第一行有一条隐式的语句super();,
        //会访问父类中空参数的构造函数,且子类中所有的构造函数默认第一行
        // 都是super();
               
        }
}
//当父类中没有空参数的构造函数时,子类必须通过手动super语句形式来指定要访问的父类构造函数,
//当然,子类的构造函数第一行也可以手动指定this语句来访问本类中的构造函数,但是要记住,,
//子类中至少要有一个构造函数会访问父类中的构造函数

作者: 陈云帆    时间: 2012-7-10 23:48
首先a是局部变量,作用范围就是fu(),在子类中是看不到的,更无法覆盖;
实例化子类,会逐级找到并调用父类的构造函数,这就是出现4,5的原因。
作者: 陈云帆    时间: 2012-7-10 23:48
首先a是局部变量,作用范围就是fu(),在子类中是看不到的,更无法覆盖;
实例化子类,会逐级找到并调用父类的构造函数,这就是出现4,5的原因。
作者: 贾飞雨    时间: 2012-7-10 23:57

//把楼主的代码修改了一下来说明问题,

class  fu
{
         String name = "李四";
                        int age = 45;
        fu()
         {       int a=4;
               // System.out.println(a);
        }
}

class zi extends fu
{
               
                 String name = "李五";
                 int age = 20;
        zi()
        {     
                                //在建立对象的时候,子类会调用父类的构造方法来帮助其初始化,
                                //调用了fu类的构造方法,所以先打印了4,然后有自己打印了自己的a=5,
                int a=5;
               // System.out.println(a);
        }
}
class  name
{
        public static void main(String[] args)
        {

                                zi x=new zi();
                                fu f = new fu();
                                System.out.println(x.name+"***"+x.age);
                                System.out.println(f.name+"***"+f.age);
                                /*运行结果,
                                李五***20
                                李四***45
                                请按任意键继续. .
                                必须没有被改变啊*/
           }      
        }
}
//问题一、子类覆盖父类的对象值之后,父类的值会改变吗??
//   能不能用一个小代码说明一下。
//首先说一下,构造方法的中的变量是不会被改变的,而且也不可能被复写,
//它是用来初始化对象的,怎么可能被子类改变父类的
//构造方法呢?

//然后父类的成员变量也不会被改变,你继承了父类的,也继承了父类的成员变量,指的是没有被Private修饰的
//成员变量,你改变了也是改变了你自己的,父类的还是父类的,
//这个就像毕老师举的那个例子,毕姥爷的年龄是45,毕老师是25,毕老师继承了毕姥爷的年龄属性,但是他有他自己的年龄
//25,毕姥爷也不会随着他儿子的年龄是25就变成了25,是不是。




作者: 邱泉    时间: 2012-7-11 00:12
本帖最后由 邱泉 于 2012-7-11 00:17 编辑

问题一:
我拿一个具体的例子来给你说明
class fu
{
        int a=1;
        int b=5;
        public void method()
        {
                System.out.println(a);  //在父类中查看a的值
        }
}

class zi extends fu
{
        int a=2;
        public void method()
        {
                System.out.println(a);  //在子类中查看a的值
        }
        public void supermethod()
        {
                System.out.println(super.a);  //在子类中查看父类的a的值。
        }
        public void bmethod()
        {
                System.out.println(b); //在子类中访问在父类中定义,但在子类中没有定义的变量b
        }
}

class DemoTest  
{
        public static void main(String[] args)
        {
                fu f = new fu();
                zi z = new zi();

                f.method();
                z.method();
                z.supermethod();
                z.bmethod();
        }
}
/*
输出结果:
1
2
1
5
*/
/*
说明:1.当子类中有和父类同名的成员变量a时,当用对象访问该变量a时,默认为this.a(默认情况下this是省略的),也就是说此时父类对象调用父类的a变量,子类对象调用子类的
a变量。
2.子类对象可以通过super.a的形式访问父类中的a变量。
3.若父类中定义的变量b,在子类中没有定义,那么子类对象访问b时,实际上访问的是父类中的b变量(也就是说b变量前默认添加了super关键字,即super.b)。

*/

问题二:
在创建子类的对象时,子类的构造函数会默认调用父类的无参数的构造函数。即代码实际上为以下形式:

class  fu
{
        fu()
         {       int a=4;
                System.out.println(a);
        }
}

class zi extends fu
{
        zi()
        {      
                super(); //此处是系统隐式添加的,调用父类的无参数的构造函数。此处打印4
                int a=5;
                System.out.println(a);  //此处打印5
        }
}
class  name
{
        public static void main(String[] args)
        {
               
                zi x=new zi();
               
        }
}

最后吐槽一下,技术分太难赚了...拼了


作者: 杨贺阳    时间: 2012-7-11 00:33
高原 发表于 2012-7-10 23:42
问题1:你问的是子类中有和父类同名的成员变量吧,“对象值”这叫法太不专业了……
如果父类和子类中有非私 ...

对,就是成员变量,不知道这个怎么叫,谢谢你的回答。你写的东西我理解了半天终于有点明白了。
问下你说的,不叫覆盖,叫什么呢???
你还没回答我第一个问题,父类的成员变量的值到底变了吗?
最后你说的左边右边 ,完全不懂。。。还是谢谢了~
作者: 杨贺阳    时间: 2012-7-11 01:00
菠菜(yinshi) 发表于 2012-7-10 23:44
class  fu
{
        fu()

//当父类中没有空参数的构造函数时,子类必须通过手动super语句形式来指定要访问的父类构造函数,
//当然,子类的构造函数第一行也可以手动指定this语句来访问本类中的构造函数,但是要记住,,
//子类中至少要有一个构造函数会访问父类中的构造函数
这一段,学习了~谢谢!
作者: 杨贺阳    时间: 2012-7-11 01:01
yufeiant 发表于 2012-7-10 23:57
//把楼主的代码修改了一下来说明问题,

class  fu

明白了!父类的构造函数不能被修改!是吧?如果是子类父类有相同的成员函数,调用子类就显示子类的成员函数,是吧!?
作者: 杨贺阳    时间: 2012-7-11 01:04
邱泉 发表于 2012-7-11 00:12
问题一:
我拿一个具体的例子来给你说明
class fu

很详细,带我读了一遍。
在创建子类的对象时,子类的构造函数会默认调用父类的无参数的构造函数。
super(); //此处是系统隐式添加的,调用父类的无参数的构造函数。此处打印4
这两句注释,这两句话很专业,谢谢!明白了~
作者: 刘煜    时间: 2012-7-11 02:07
本帖最后由 刘煜 于 2012-7-11 02:22 编辑

对于问题一:你说的对象值应该是指成员变量,子类的成员变量可以覆盖父类的成员变量,但是不能改变父类的成员变量,实质是Java继承中,成员变量(包括静态变量,实例变量,常量)没有覆盖(override)一说,应该叫隐藏(hidden),子类的同名变量只是隐藏(hidden)了父类的同名变量。子类可以通过super来实现对父类成员变量的访问。这里我也说一下继承的机制,帮助你理解:JVM把父类源代码编译成字节代码时,对直接继承和覆盖重写的成员,操作是不同的!对于直接继承的成员,并不把其代码加到子类的代码中,但会保留一个类似引用的对象(我不知道,我自己的理解和设想),起到了隐藏的作用,用来指向父类中相应的成员;而对于被覆盖重写过的成员方法和同名成员变量来说,则像对待子类中的其他自有成员一样,在分配空间是给他们分配自己的空间,也就是说,在编译后的子类字节代码中会有这些成员的代码。这里覆盖后的成员变量有不同于父类成员变量的空间,所以不会修改父类的成员变量。同时也举个简单的例子:
class  fu
{
        int a=4;
        fu()
         {      
                System.out.println(a);
        }
}

class zi extends fu
{
        int a=5;
        zi()
        {      
               
                System.out.println(a);
        }
}
class  name
{
        public static void main(String[] args)
        {
               
                zi x=new zi();
               
        }
}

运行结果是:
4
5
对于问题二:以上例子同时也说明了子类在创建对象的时候,调用了父类的构造方法。子类的构造函数中默认第一行有一条隐式语句super(),该语句会访问父类中空参数的构造函数,而且是子类中所有构造函数第一行默认都有该语句,所以主函数中创建子类对象的时候会调用父类的构造函数,输出4,然后再调用子类的构造函数,输出5
为什么子类一定要访问父类中的构造函数?因为父类中的数据,子类可以直接获取,因此在子类对象建立是,需要先查看父类是如何对这些数据进行初始化的,所以子类在对象初始化时,要先访问一个父类中的构造函数。
需要注意的是:可以通过手动定义
super语句的方式访问父类中指定的构造函数;如果父类中有含参构造函数而没有空参数的构造函数,那么子类中的构造函数的第一行需要手动加上父类的含参构造函数;super语句一定定义在子类构造函数的第一行,如果有this语句,就不能有super语句,因为他们都必须在第一行。








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