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

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 乔九 中级黑马   /  2012-9-3 21:49  /  2641 人查看  /  14 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

class Demo
{
        public int get()
        {
                return 4;
        }
}
        
class Demos extends Demo
{
     public int get()
        {
                return 5;
        }
    public static void main(String[] args)
        {
                Demo s=new Demos();
                System.out.println(s.get());
        }
}
结果问什么是5,不是4.

评分

参与人数 1技术分 +1 收起 理由
唐志兵 + 1 赞一个!

查看全部评分

14 个回复

倒序浏览
1)子父类中的成员关系
                A:成员变量
                        在子类方法中使用一个变量时:
                        首先,在方法的局部变量中找这个变量,有则使用。
                        否则,在本类中找成员变量,有则使用。
                        否则,在父类中找成员变量,有则使用。
                        否则,报错。
                B:成员方法
                        用子类对象使用一个方法时。
                        首先,在子类中找这个方法,有则使用。
                        否则,在父类中找这个方法,有则使用。
                        否则,报错。

                        当子父类中的方法名相同时的现象被称为重写。

                        重写和重载的区别?
                        重载:在同一类中。方法名相同,参数列表不同。

                        重写:在不同类中(子父类中)。
                              方法声明相同(返回类型,方法名,参数列表)。

                        重载可以改变返回类型。

                        重写需要注意:
                                **子类方法的访问权限要大于等于父类方法的访问权限。
                                **静态只能重写静态。一般不会出现。
                C:构造方法
                        **子类的实例化过程
                                ***子类创建对象时,会先去创建父类的对象。
                                    默认是去调用父类的无参构造方法。
                                ***子类构造方法中,第一行默认是super()
                                ***为什么子类中第一行会默认有super()
                                        因为他继承父类的成员使用,使用前这些成员必须初始化,
                                        而他们是父类的成员,所以,必须通过父类进行初始化。
                                        所以,会先创建一个父类的对象。
                        **当父类没有无参构造方法时
                                必须使用this或者super调用其他的构造方法。
        2)this和super的区别
                this:代表本类对象的引用。
                super:代表父类的存储空间。

                用法很相似。
  你既然是用继承  就应该知道他们之间谁调用谁,是么时候调用,

评分

参与人数 1技术分 +1 收起 理由
唐志兵 + 1 赞一个!

查看全部评分

回复 使用道具 举报
子类Demos继承了父类Demo,并覆写了父类的方法。
重点在下面的这段代码
Demo s=new Demos();
这里通过子类新建一个父类对象,发生了向上类型的转化!那么新生成的父类的对象中的方法为子类覆写后的方法,所以得到上面的结果!~
回复 使用道具 举报
哥们,这个是多态的问题。
Demo是父类,Demo d = new Demos(); 父类创建子类对象,发生向上转型,但是发生向上转型后,新建的对象所有的属性和方法均为子类Demos
对象的属性和方法。
所以d.get();打印的是子类的值。
举个例子:
动物  animal = new 猫();  我要animal你给我了一个猫,这个也是无可厚非的,毕竟是动物嘛,但是这个动物的属性是猫呀,
它的属性之一就是抓老鼠,看不了家。
回复 使用道具 举报
在这里涉及到了覆盖和多态,当父类引用指向子类对象时在编译时期父类有get方法,所以编译通过,在运行时期因为子类覆盖了父类的get方法,所以最后执行的是子类的get方法输出结果为5而不是4

class Demo
{
         int num = 3;
        public int get()
         {
                 return 4;
         }
                 public static void show()
         {}
}
         
class Demos extends Demo
{
         int num = 6;
      public int get()
         {
                 return 5;
         }
                 public static void show(){}
     public static void main(String[] args)
         {
                 Demo s=new Demos();
                 System.out.println(s.get());
         }
}
简单跟你总结几条规律吧:
1,父类引用调用成员变量
   以你的程序为例: Demo s=new Demos();System.out.println(s.num);输出的结果为3而不是6.
因为子类继承父类而子父类中有同名成员变量时,编译时期和执行时期都是看Demo s=new Demos();的左边
最后输出的结果必然为父类中的num。
2,父类引用调用成员函数
   Demo s=new Demos();System.out.println(s.get());在编译时期看Demo s=new Demos();的左边如果有get方法编译通过否则编译失败,在运行时期看等号的右边,因为子类覆盖了父类的get方法,所以执行的是子类中get方法。
3,父类引用调用静态成员函数
   因为静态随着类的加载而加载,可以用类名直接调用。所以在编译时期和运行时期都看Demo s=new Demos();的左边,结果执行的必然是父类中的静态方法。
回复 使用道具 举报
在这里涉及到了覆盖和多态,当父类引用指向子类对象时在编译时期父类有get方法,所以编译通过,在运行时期因为子类覆盖了父类的get方法,所以最后执行的是子类的get方法输出结果为5而不是4

class Demo
{
         int num = 3;
        public int get()
         {
                 return 4;
         }
                 public static void show()
         {}
}
         
class Demos extends Demo
{
         int num = 6;
      public int get()
         {
                 return 5;
         }
                 public static void show(){}
     public static void main(String[] args)
         {
                 Demo s=new Demos();
                 System.out.println(s.get());
         }
}
简单跟你总结几条规律吧:
1,父类引用调用成员变量
   以你的程序为例: Demo s=new Demos();System.out.println(s.num);输出的结果为3而不是6.
因为子类继承父类而子父类中有同名成员变量时,编译时期和执行时期都是看Demo s=new Demos();的左边
最后输出的结果必然为父类中的num。
2,父类引用调用成员函数
   Demo s=new Demos();System.out.println(s.get());在编译时期看Demo s=new Demos();的左边如果有get方法编译通过否则编译失败,在运行时期看等号的右边,因为子类覆盖了父类的get方法,所以执行的是子类中get方法。
3,父类引用调用静态成员函数
   因为静态随着类的加载而加载,可以用类名直接调用。所以在编译时期和运行时期都看Demo s=new Demos();的左边,结果执行的必然是父类中的静态方法。
回复 使用道具 举报
这是个多态的问题:
    Demo s=new Demos();//
   这句话就是多态的表现:   表示父类Demo的引用 s 指向了 子类 Demos的一个对象,
             当调用了get()方法时,会直接执行 子类里的get()方法,而不是父类的get方法 所以输出5。
          你可以这样想:
                  在继承时,子类是重写了get()方法,而现在 父类的引用已经指向了子类对象的空间,而子类空间已经有这个方法,它当然不会舍近求远去执行父类的方法嘛 ,是不
   
回复 使用道具 举报
思想如下:
父类有个 num=5; 子类重新定义了自己的num=4;
Demo s=new Demos(); 这是一个父类引用指向了子类对象。
内存中 其实有两个 num。
但是如果子类有自己的属性,则访问自己的属性。//这并不是重写。重写只发生在一般的函数上。
如果子类 覆写了 父类的方法,成员函数有覆盖的特性。所以会调用子类重写过的方法。
如果子类有特有方法。那么父类引用在调用时,只能调用父类中的方法,
不能调用子类特有的方法。 这也是多态的局限性。

另外再给你总结一个结论:
1,成员变量。
        编译时期:查看引用型变量所属的类中是否有被调用的成员变量。如果有,编译通过,如果没有,编译失败。
        运行时期:也是查看引用型变量所属的类中的成员变量。
        简单说:对于成员变量在多态调用时,编译和运行都看等号的左边。
2,成员函数。
         简单说:对于成员函数在多态调用时,编译看左边,运行看右边。
         因为在子父类中,成员函数有覆盖的特性。
3,静态函数。
        简单说:对于静态函数在多态调用时,编译和运行都看等号的左边。
回复 使用道具 举报
黑马--张帅 发表于 2012-9-3 22:20
在这里涉及到了覆盖和多态,当父类引用指向子类对象时在编译时期父类有get方法,所以编译通过,在运行时期 ...

网速的问题一不小心就发了两条
回复 使用道具 举报
关键看new的是什么对象
回复 使用道具 举报
Demo s=new Demos();
定义s是父类,后面new的是子类,不知是有意还是无意。
如果是无意那么就是个子父类继承的时候,函数覆盖问题。
回复 使用道具 举报
{:soso_e110:}围观围观
回复 使用道具 举报
看不懂···                                    
回复 使用道具 举报
父类Demo可以创建子类Demos的对象,但是别忘了,s引用的是对象,这里只有一个对象,就是Demos(),所以,当然运行子类中的方法。
回复 使用道具 举报
动物  animal = new 猫();  这里new的是猫,所以应该是抓鱼,虽然你将猫提升成了动物,但调用其方法还应该是抓鱼。不可能让它去看家。这是我的理解,可能不对,请拍砖。
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马