黑马程序员技术交流社区

标题: 关于继承中变量覆盖问题 [打印本页]

作者: 李新辉    时间: 2013-11-4 23:13
标题: 关于继承中变量覆盖问题
本帖最后由 李新辉 于 2013-11-5 11:44 编辑

复制代码
  1. class Super
  2. {
  3.         int i = 20;
  4.         public Super(String a)
  5.         {                  
  6.                 i=1;
  7.         }
  8.         public Super()
  9.         {
  10.                 System.out.println("b  "+i);//b  20
  11.                 i += 2;
  12.                 System.out.println("c  "+i);//c  22
  13.         }
  14. }
  15. class Demo extends Super
  16. {
  17.         public Demo (String a)
  18.         {
  19.                 System.out.println("d  "+i);//d  22
  20.                 i = 5;
  21.                 System.out.println("e  "+i);//e  5
  22.         }
  23.         public static void main(String[] args)
  24.         {
  25.                 int i = 4;
  26.                 System.out.println("a  "+i);//a  4
  27.                 Super d=new Demo("A");
  28.                 System.out.println("f  "+i);//f  4
  29.                 System.out.println(d.i);//5
  30.         }
  31. }
复制代码
  1. class Super
  2. {
  3.         int i = 20;
  4.         public Super(String a)
  5.         {                  
  6.                 i=1;
  7.         }
  8.         public Super()
  9.         {
  10.                 System.out.println("a  "+i);//a  20
  11.                 i += 2;
  12.                 System.out.println("b  "+i);//b  22
  13.         }
  14. }
  15. class Demo extends Super
  16. {
  17.         static int i = 4;
  18.         public Demo (String a)
  19.         {
  20.                 System.out.println("c  "+i);//c  4
  21.                 i = 5;
  22.                 System.out.println("d  "+i);//d  5
  23.         }
  24.         public static void main(String[] args)
  25.         {
  26.                 Super d=new Demo("A");
  27.                 System.out.println("e  "+i);//e  5
  28.                 System.out.println(d.i);//22
  29.         }
  30. }
复制代码
一个结果是5
一个结果是22

求高人指点,这结果怎么来的
我很迷惑…………

作者: zdrain    时间: 2013-11-4 23:32
第一个程序的运行结果是22,这个因为static和成员变量存储在不同区域有关,Demo类中的i是static的,包括i=5,建立对象后,访问的就是堆内存中的i,结果就是20+2=22

第二个程序结果是5,因为都是堆内存中的i,最后执行到i=5,所以i的最终值就是5
作者: 寻丶丶觅    时间: 2013-11-4 23:39
class Super
{
        int i = 20;
        public Super(String a)
        {                  
                i=1;
        }
        public Super()
        {
                i += 2;
        }
}
class Demo extends Super
{
                //这个相当于复写了变量i
        static int i = 4;
        public Demo (String a)
        {
                                //这里隐式的有super();所以父类i初始化后为22
                i = 5;//这个i,因为本类有,相当于this.i
        }
        public static void main(String[] args)
        {
                Super d=new Demo("A");
                                //多态,常量看左面
                System.out.println(d.i);
        }
}
-------------------------------------------------
class Super
{
        int i = 20;
        public Super(String a)
        {                  
                i=1;
        }
        public Super()
        {
                i += 2;
        }
}
class Demo extends Super
{

        public Demo (String a)
        {
                                ////这里隐式的有super();所以父类i初始化后为22
                i = 5;//这个i相当于super.i,在父类初始化后又对i重新赋值5
        }
        public static void main(String[] args)
        {
                int i = 4;
                Super d=new Demo("A");
                System.out.println(d.i);
                                //还是调用的父类的i,你写这两个调用的都是父类的i,关键是你没搞懂赋值过程
        }

}


作者: 魏-玉-彪    时间: 2013-11-4 23:44
  1. class Super
  2. {
  3.         int i = 20;
  4.         public Super(String a)
  5.         {                  
  6.                 i=1;
  7.         }
  8.         public Super()          //第二步,初始化父类并且执行构造方法, i=22
  9.         {
  10.                 i += 2;
  11.         }
  12. }
  13. class Demo extends Super
  14. {
  15.               static int i = 4;      //在这里,子类和父类具有同名变量,如果没

  16. //这里没有定义   static int i = 4;  下面这个语句将给父类变量赋值
  17. //由于在子类中定义了 这个变量,所以下面语句赋值给本类中的i 而最后
  18. //打印的是父类中的 i.
  19.         public Demo (String a)
  20.         {
  21.                 i = 5;
  22.         }
  23.         public static void main(String[] args)
  24.         {
  25.                 Super d=new Demo("A"); //第一步  
  26.                 System.out.println(d.i);  //第三步,打印父类中变量
  27.         }
  28. }
复制代码

作者: Clare0621    时间: 2013-11-5 00:15
本帖最后由 Clare0621 于 2013-11-5 12:57 编辑

顺序反了,根据你重新编辑的代码,下面程序一指楼主第二个程序,程序二指第一个程序:

// 程序一:子类中并未定义成员变量。因此子类构造函数里面的i操作的是父类的属性i,可理解为:super.i = 5;在子类实例化过程中会先调用父类构造函数,在调用子类构造函数,最后打印的d.i是父类的属性i,因此为5.


//程序2:static int i = 4,定义了一个静态成员变量变量或叫类变量。因为子类有了属性i,则子类构造函数里面的i = 5,可理解为this.i = 5;而最后打印d.i的值同样为父类的i,但与程序一不同的就是子类构造函数里面的语句 i = 5,操作的是子类变量与父类无关,因而d.i只经过父类构造函数初始化为22.
另:可在输出d.i语句后面,加上一句:System.out.println(this.i)加以验证,输出的值应为5

作者: heke    时间: 2013-11-5 00:57
成员函数在多态调用时,编译看左边,运行看右边。Demo2中i是成员函数中的局部变量,所以调用的是子的i,先初始值i=4,new Demo2("A")后变为5
我对程序一的简化
  1. class Super
  2. {
  3.         int i = 20;
  4.    
  5. }
  6. class Demo2 extends Super
  7. {
  8.         public Demo2 (String a)
  9.         {
  10.                
  11.                 i = 5;
  12.                
  13.         }
  14.         public static void main(String[] args)
  15.         {
  16.                 int i = 4;

  17.                 Super d=new Demo2("A");

  18.                 System.out.println(d.i);
  19.         }
  20. }
复制代码
在多态中成员变量,无论编译和运行,都参考左边的,即引用型变量所属的类型。也就是说父类中有自己的变量,则先找父类自己的成员。所以造成第二个程序结果为22
我把第二个程序简化了,意思一样的
  1. class Fu
  2. {
  3.         int i = 22;

  4. }
  5. class Demo extends Fu
  6. {
  7.         static int i = 4;
  8.         public static void main(String[] args)
  9.         {
  10.                 Fu d=new Demo();
  11.                 System.out.println(d.i);
  12.         }
  13. }
复制代码
总结:因为当调用静态方法时,只要建立子类对象,父类与子类中的静态方法都会随之加载入内存,是不需要调用就可直接用类名.方法名的,而不需要对象。只要引用还存在,就看引用变量的类型。
作者: YUStone    时间: 2013-11-5 02:54
1.子类继承必须调用父类构造函数
2.默认调用无参构造函数
3.子类和父类都只有有参构造函数,而子类没有显示调用super(参数),会报错
4.两个程序实际返回的都是父类的变量,可以在Demo1中添加super.i测试
class Super
{
        int i = 20;
        public Super(String a)
        {                  
                i=1;
        }
        public Super()
        {
                System.out.println("b  "+i);//b  20
                i += 2;
                System.out.println("c  "+i);//c  22
        }
}
class Demo extends Super
{
        public Demo (String a)
        {
                System.out.println("d  "+i);//d  22
                i = 5;
                System.out.println("e  "+i);//e  5
                                System.out.println(super.i);
        }
        public static void main(String[] args)
        {
                int i = 4;
                System.out.println("a  "+i);//a  4
                Super d=new Demo("A");
                System.out.println("f  "+i);//f  4
                System.out.println(d.i);//5
        }
}
作者: 黄炳期    时间: 2013-11-5 08:34
帖子已重新分类,如果问题还没有解决,可重新提问
作者: 李新辉    时间: 2013-11-5 11:06
黄炳期 发表于 2013-11-5 08:34
帖子已重新分类,如果问题还没有解决,可重新提问

经常打不开论坛……
烦死了……


Bad Request

Your browser sent a request that this server could not understand.
Size of a request header field exceeds server limit.
Cookie: Ms5p_2132_saltkey=BHEmdzgs; Ms5p_2132_lastvisit=1383212933; Ms5p_2132_client_created=1383216576; Ms5p_2132_client_token=33DD081EE214AEB049FEB7D65EAC0598; Ms5p_2132_auth=25fal8heQEC

360总是出这毛病
其他浏览器就没事……

作者: 黄炳期    时间: 2013-11-5 11:11
李新辉 发表于 2013-11-5 11:06
经常打不开论坛……
烦死了……

不会啊,我就是用360浏览器的,正常的

作者: 李新辉    时间: 2013-11-5 11:29
黄炳期 发表于 2013-11-5 11:11
不会啊,我就是用360浏览器的,正常的

那就不知道了  
也没上乱七八糟的网站   就是第二次出这问题了
作者: 李新辉    时间: 2013-11-5 11:34
寻丶丶觅 发表于 2013-11-4 23:39
class Super
{
        int i = 20;

静态变量能覆盖父类非静态变量???
不能吧……

主函数定义的    i   呢???
作者: 李新辉    时间: 2013-11-5 11:43
Clare0621 发表于 2013-11-5 00:15
程序一:子类中并未定义成员变量,static int i = 4,定义了一个静态变量或叫类变量。因此子类构造函数里面 ...

d.i
调用不是类变量   i  吗?
代码我加上了打印语句
还有  输出结果   
麻烦再帮我看看
作者: Clare0621    时间: 2013-11-5 12:52
李新辉 发表于 2013-11-5 11:43
d.i
调用不是类变量   i  吗?
代码我加上了打印语句

我原回复说错了,根据你重新编辑的代码看:
程序一:子类未定义成员变量,因此子类构造函数Demo里面的i可看成:super.i = 5,因而后面打印的 d.i 值也为5;
程序二:子类定义了静态成员变量,所以子类构造函数里面的 i=5可看成是:this.i = 5;操作的是子类成员变量i,与父类无关
最后,俩个程序打印的 d.i 值都是父类的成员变量 i ,因为多态时,成员变量并不具备多态性。也即不管编译还是运行,都参考左边即引用的类型,这里是父类。
作者: 李新辉    时间: 2013-11-5 14:50
本帖最后由 李新辉 于 2013-11-5 15:00 编辑
Clare0621 发表于 2013-11-5 00:15
顺序反了,根据你重新编辑的代码,下面程序一指楼主第二个程序,程序二指第一个程序:

// 程序一:子类中 ...

顺序反了,根据你重新编辑的代码,下面程序一指楼主第二个程序,程序二指第一个程序:

// 程序一:子类中并未定义成员变量。因此子类构造函数里面的i操作的是父类的属性i,可理解为:super.i = 5;在子类实例化过程中会先调用父类构造函数,在调用子类构造函数,最后打印的d.i是父类的属性i,因此为5.


                System.out.println("f  "+i);  //那么这个位置打印这个     i   又是怎么回事呢?
                System.out.println("   "+d.i);//5


//程序2:static int i = 4,定义了一个静态成员变量变量或叫类变量。因为子类有了属性i,则子类构造函数里面的i = 5,可理解为this.i = 5;而最后打印d.i的值同样为父类的i,但与程序一不同的就是子类构造函数里面的语句 i = 5,操作的是子类变量与父类无关,因而d.i只经过父类构造函数初始化为22.
另:可在输出d.i语句后面,加上一句:System.out.println(this.i)加以验证,输出的值应为5
                                                      //主函数为静态,不可能有this引用!!!我已经验证过……

System.out.println("   "+d.i);//22我认为此处打印的是对象中    i    ,对象中还是父类继承来的i     
                                           //如果没有对象的存在,那么打印   i   就是静态的类变量   i=4


作者: Clare0621    时间: 2013-11-5 16:36
    System.out.println("f  "+i);  //那么这个位置打印这个     i   又是怎么回事呢?——————>这个  i   是主函数里面的 i 啊,那是个局部变量,在主函数有效,所以打印a和f都是4.
    System.out.println("   "+d.i);//5

//主函数为静态,不可能有this引用!!!我已经验证过…——————对的

System.out.println("   "+d.i);//22我认为此处打印的是对象中    i    ,对象中还是父类继承来的i     
                                           //如果没有对象的存在,那么打印   i   就是静态的类变量   i=4————————>听不懂,如果不建立对象,构造函数根本不会被调用,那里根本执行不到啊

作者: 李新辉    时间: 2013-11-5 16:54
Clare0621 发表于 2013-11-5 16:36
System.out.println("f  "+i);  //那么这个位置打印这个     i   又是怎么回事呢?——————>这个   ...

不建立对象   类加载  静态变量已经存在   这时候直接打印   i   就是  静态变量 而已
静态给类 初始化的嘛……

对不??
作者: Clare0621    时间: 2013-11-5 17:25
李新辉 发表于 2013-11-5 16:54
不建立对象   类加载  静态变量已经存在   这时候直接打印   i   就是  静态变量 而已
静态给类 初始化的 ...

恩,对程序而如此
作者: 何超    时间: 2013-11-5 20:02
heke 发表于 2013-11-5 00:57
成员函数在多态调用时,编译看左边,运行看右边。Demo2中i是成员函数中的局部变量,所以调用的是子的i,先初 ...

1     总结:因为当调用静态方法时,只要建立子类对象,父类与子类中的静态方法都会随之加载入内存,是不需要调用就可直接用类名.方法名的,而不需要对象。        
2     只要引用还存在,就看引用变量的类型。

1和2有关系么  为什么我看半天看不出来关系···1我知道 但是在这个程序里好像没体现啊
2是什么意思  说的是 父类引用指向子类对象么      !!!



作者: 何超    时间: 2013-11-5 20:07
heke 发表于 2013-11-5 00:57
成员函数在多态调用时,编译看左边,运行看右边。Demo2中i是成员函数中的局部变量,所以调用的是子的i,先初 ...

第一个结果为5的程序  最后 d.i 不是应该看父类的  i 么  前面也是父类引用指向子类对象  成员变量应该看父类里面的啊  跟 主函数里定义了一次  i  有什么关系   求告知!!!
作者: 李新辉    时间: 2013-11-5 20:09
那位大神能详细的给  我讲解一下  代码中每一个打印语句中是  变量  i  的出处啊?
还是不太明白……
作者: 李新辉    时间: 2013-11-5 20:11
何超 发表于 2013-11-5 20:02
1     总结:因为当调用静态方法时,只要建立子类对象,父类与子类中的静态方法都会随之加载入内存,是不 ...

你自己运行一下就知道了  
每一个打印语句   打印的变量  是哪里来的  你搞得清楚不?
作者: 何超    时间: 2013-11-5 20:16
李新辉 发表于 2013-11-5 20:11
你自己运行一下就知道了  
每一个打印语句   打印的变量  是哪里来的  你搞得清楚不? ...

我也是结果为 5 的那一句搞不清······跟你一样····我的想法还是应该是输出 22:L
作者: 何超    时间: 2013-11-5 20:36
上面说错了 = = 我是想不通为什么是 5

想了半天 最后发现其实应该就是 this.i  和  super.i 的问题  你下面那个代码在子类中直接初始化了一次 i  并且在构造方法中默认写的 i=赋值  此时默认为  this.i=赋值   所以你改变的是子类的 i   但是最后的d.i 其实运行的是父类的i  所以是22

同理  对于你上面那个代码  最后运行的也是父类的 i  只是你在子类的最外面没有定义一个  i 并且你子类的构造方法还是写的  i=赋值 此时默认为  super.i=赋值  此时 父类中的  i  就被你改变了   所以最后输出的5  其实还是  父类的 i  只不过是被你改变了值罢了

这样理解应该问题了吧
作者: 何超    时间: 2013-11-5 20:38
你可以试下 你把上面那个代码 也在子类的最外面定义一次  i   那么你输出的结果也是22  所以就是 this 和 super的问题了
作者: 李新辉    时间: 2013-11-5 21:14
何超 发表于 2013-11-5 20:38
你可以试下 你把上面那个代码 也在子类的最外面定义一次  i   那么你输出的结果也是22  所以就是 this 和 s ...

都定义了 就是多态
这在比老师的视频中讲过的   
这个我清楚……
就这样吧  
太饶人了……

作者: 何超    时间: 2013-11-5 21:33
李新辉 发表于 2013-11-5 21:14
都定义了 就是多态
这在比老师的视频中讲过的   
这个我清楚……

= = 确实都定义了我知道  但是 你下面那个定义的 i  是静态全局变量   而你上面那个 i  是局部变量  两个不一样···所以导致最后结果不同   确实很麻烦  尼玛  我想了好久 搞得我今天视频都没看完  不知道能不能赶上12.1的那期
作者: 李新辉    时间: 2013-11-5 22:39
何超 发表于 2013-11-5 21:33
= = 确实都定义了我知道  但是 你下面那个定义的 i  是静态全局变量   而你上面那个 i  是局部变量  两个 ...

我这两天也是这问题  
视频也没看……
你尽快吧  
这问题留作以后吧  
记着它

经验多了
慢慢应该就知道了
作者: 李新辉    时间: 2013-11-6 14:08
那位大神还有不同见解的
也来说说呀
分享一下……
作者: The_Wizard    时间: 2013-11-6 15:57
package answer;

class Super

{

        int i = 20;

        public Super(String a)

        {                  

                i=1;

        }

        public Super()

        {

                System.out.println("a  "+i);//a  20

                i += 2;

                System.out.println("b  "+i);//b  22

        }

}

public class Demo2 extends Super

{

        static int i = 4;

        public Demo2 (String a)

        {

                System.out.println("c  "+i);//c  4

                i = 5;

                System.out.println("d  "+i);//d  5

        }

        public static void main(String[] args)

        {

                Super d=new Demo2("A");

                System.out.println("e  "+i);//e  5,这个 i 是本类中的 i。

                System.out.println(d.i);//22, 这个 i 是Super 类中的 i。
               
               
              /*加上后边两句,应该就比较明显了。其实就是多态只针对非静态、非私有的函数。前面定义的d是一个Super类,它的 i 不就是22么。
               * 将d转换成Demo2,i 就是5。
               */
                Demo2 e = (Demo2)d;
               
                System.out.println(e.i);//5

        }

}

作者: 李新辉    时间: 2013-11-6 23:50
本帖最后由 李新辉 于 2013-11-7 00:07 编辑
The_Wizard 发表于 2013-11-6 15:57
package answer;

class Super

那么,那个静态的  i  去哪了了呢?
一直都为  4 没有变过  ,是吗?
那么静态的  i  在什么时候会变化呢??


静态的  i   在dome2()中被父类中非静态的   i   覆盖并重新赋值为 5 了吗?

非静态不能覆盖静态吧……

        public class Demo2 extends Super
        {
                static int i = 4;
                public Demo2 (String a)
                {
                        System.out.println("c  "+i);//c  4//这 打印的是什么时候的   i   呢?为什么?  相当于 this.i 吗?
                        i = 5;
                        System.out.println("d  "+i);//d  5
                }
         }
                 public static void main(String[] args)
                 {
                        Super d=new Demo2("A");
                                System.out.println("e  "+i);//e  5,这个 i 是本类中的 i。//确切的说是本类对象中的  i 吧(this.i)
                        System.out.println(d.i);//22, 这个 i 是Super 类中的 i。                     
                      /*加上后边两句,应该就比较明显了。其实就是多态只针对非静态、非私有的函数。
                         前面定义的d是一个Super类, 它的 i 不就是22么。        //那么静态呢?
                        * 将d转换成Demo2,i 就是5。                                    
                        */
                         Demo2 e = (Demo2)d;                 
                        System.out.println(e.i);//5
                  }
        }



作者: The_Wizard    时间: 2013-11-7 01:13
System.out.println("c  "+i);//c  4//这 打印的是什么时候的   i   呢?为什么?  相当于 this.i 吗?这个应该是
Demo2.i,这个你不说,我还没有发现呢,在构造函数中居然可以使用静态成员。
System.out.println("e  "+i);//e  5,这个 i 是本类中的 i。//确切的说是本类对象中的  i 吧(this.i),同样,这里也是Demo2.i。
前面定义的d是一个Super类, 它的 i 不就是22么。        //那么静态呢?这里d是Super类型的,Super哪里有静态的成员变量i,它的i是那个非静态的。
作者: 黄炳期    时间: 2013-11-7 09:04
帖子已经分类。还没明白的,认真整理答案,会有你想要的。
也可以再看看视频
作者: 李新辉    时间: 2013-11-7 14:49
The_Wizard 发表于 2013-11-7 01:13
System.out.println("c  "+i);//c  4//这 打印的是什么时候的   i   呢?为什么?  相当于 this.i 吗?这个 ...

System.out.println("c  "+i);//c  4//这 打印的是什么时候的   i   呢?为什么?  相当于 this.i 吗?这个应该是
Demo2.i,这个你不说,我还没有发现呢,在构造函数中居然可以使用静态成员。
System.out.println("e  "+i);//e  5,这个 i 是本类中的 i。//确切的说是本类对象中的  i 吧(this.i),  
                                                      //同样,这里也是Demo2.i。 这是静态成员的调用方式啊……
                                                      //你意思是这里调用的是子类的静态成员啦??  那么父类继承来的非静态的  i  呢??被覆盖??
                                                      //子类的静态成员把从父类继承来的非静态  i  覆盖掉了吗?不能吧……
前面定义的d是一个Super类, 它的 i 不就是22么。        //那么静态呢?这里d是Super类型的,Super哪里有静态的成员变量i,它的i是那个非静态的。

作者: 李新辉    时间: 2013-11-7 15:09
本帖最后由 李新辉 于 2013-11-7 15:11 编辑
魏-玉-彪 发表于 2013-11-4 23:44

13.class Demo extends Super

14.{

15.              static int i = 4;      //在这里,子类和父类具有同名变量,如果没

16.

17.//这里没有定义   static int i = 4;  下面这个语句将给父类变量赋值 <==这个我了解,继承父类并重新赋值

18.//由于在子类中定义了 这个变量,所以下面语句赋值给本类中的i 而最后 <==这里本类中的 i  你指哪个?静态的还是父类继承来的非静态?
                                                                                                                               _
                                                                                                                              /|\
19.//打印的是父类中的 i                                                                                           |   
                                                                                                                               |
        
20.        public Demo (String a)                                                                              |            
                                                                                                                               |
21.        {                                                                                                                 |
                                                                                                                               |
  
22.                i = 5;  <==你要明白这句赋值语句之前隐式的super()把父类的 i 已经继承过来了……
                               怎么会给本类的 i 赋值呢?

23.        }

24.        public static void main(String[] args)
25.        {

26.                Super d=new Demo("A"); //第一步  

27.                System.out.println(d.i);  //第三步,打印父类中变量

28.        }

29.}


作者: 李新辉    时间: 2013-11-7 15:18
Clare0621 发表于 2013-11-5 00:15
顺序反了,根据你重新编辑的代码,下面程序一指楼主第二个程序,程序二指第一个程序:

// 程序一:子类中 ...

看来看去
发现你说的  的刚刚看懂……
似乎明白了
子类构造函数在为i  赋值的时候,本类有就在本类找  
那么,即使super()语句继承了父类的  i  ,他也在本类找???




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