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

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 创出一片辉煌 中级黑马   /  2012-7-27 01:33  /  2267 人查看  /  7 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

继承, 覆写, private, default
class Person{                //定义父类
        private void print(){
                System.out.println("Person");
        }
        public void fun(){
                this.print();                //调用父类中的print方法
        }
}

class Student extends Person{                //定义子类
        void print(){
                System.out.println("Student");
        }
}

class OverrideDemo04{
        public static void main(String args[]){
                Student s = new Student();
                s.fun();
                s.print();
        }
}
复制代码以上代码,执行的结果如下:
Person
Student
可见Student类中的print方法成功覆写,然后调用继承自Person类的fun方法时,能成功访问到Person类中的private方法。
想请问:
Student类的实例对象s,为何能通过fun方法访问到父类中的private方法?
当s调用fun方法的时候,fun方法的定义里面的this关键字不是应该等同于s么?

7 个回复

倒序浏览
本帖最后由 王志明 于 2012-7-27 02:39 编辑

楼主你理解错了,不要被运行结果的表象骗到
1. 在你的Student类中并没有覆盖父类中的print方法,因为父类中的print方法是private的,你并没有继承,不能直接访问,你在Student类中写的print方法是Student特有的,所有当你s.print()是,输出--->Student
2.当s调用fun方法的时候,fun方法的定义里面的this确实等同于s,但是在fun方法中调用的是父类的print方法

你可以用下面的代码试试看,当你将Student类中的print方法去掉时,ms中不会出现print
   Method[] ms = this.getClass().getDeclaredMethods();
   for (Method m : ms) {
       m.setAccessible(true);
      System.out.println(m.getName());
   }

点评

你的方法并不能测试有没有被覆盖,将Student类中的print方法去掉之后,已经不存在覆不覆盖。所以不能打印print证明不了什么。  发表于 2012-7-29 17:20
回复 使用道具 举报
1Student类的实例对象s,为何能通过fun方法访问到父类中的private方法?
被private修饰,只能被自己调用,这里的调用实际是指直接调用,即直接调用使用。你这里的并不是直接调用,而是通过public的fun间接的调用。这就类似定义private string name这样的私有成员,但我们可以通过public setName()来改变name值一样。
2当s调用fun方法的时候,fun方法的定义里面的this关键字不是应该等同于s么?
你在子类中没有复写父类的fun方法,当你新建一个子类实例时,在内存中是先初始化父类,由于你没有复写fun方法,在调用时,调用的是父类的fun方法,此时的this不是子类的this,而是父类的this,也就相当于子类中的super,故this并不等同于s。
回复 使用道具 举报
  1. class Person
  2. {           
  3.        String str ="Person_field";
  4.      //被final修饰的方法是不可以被子类覆盖的
  5.         final void test2()
  6.         {
  7.                 System.out.println("Person_test2");
  8.         }
  9.         //私有的方法,子类继承的时候都它都看不见
  10.         private void print()
  11.         {
  12.                 System.out.println("Person");
  13.         }
  14.         public void test()
  15.         {
  16.                 System.out.println("person_test");
  17.         }
  18.         public void fun()
  19.         {
  20.                 this.test2();//这里调用的是父类的方法,this都是隐士的。
  21.                 this.print();//这里调用的是父类的方法,this是隐士的
  22.                 this.test();//这里打印出来的结果是子类的。
  23.         }
  24. }

  25. class Student extends Person
  26. {               
  27.                String str ="Student_field";
  28.         void print()
  29.         {
  30.                 System.out.println("Student");
  31.         }
  32.         public void test()
  33.         {
  34.                 System.out.println("Student_test");
  35.         }
  36. }

  37. class OverrideDemo04{
  38.         public static void main(String args[])
  39.         {
  40.                 Student s = new Student();
  41.                 s.fun();
  42.                 s.print();
  43.                                 s.test2();
  44.                                 Person p =s;
  45.                 //p.print();//这个地方连编译都不会通过
  46.                 p.test();//这个地方调用的是子类的。
  47.                       System.out.println(p.str);//这个地方调用的是父类的字段
  48.                 System.out.println(s.str);//这个地方调用的是子类的字段;
  49.         }
  50. }
复制代码
小结:这个程序的打印结果是
Person_test2
Person
Student_test
Student
Person_test2
Student_test
楼主,其实关于继承中方法的覆盖我有时候也是蒙的,下面只是我推测的想法,希望咱们共同探讨。子类在继承父类的时候,它会跟父类说,把你的东西都给我,父类看到子类手里的extends,也是无可奈何的。但是父类也是有隐私的,保护这个隐私的关键字就是private。有时候有的父类会有自己的传家宝,这个传家宝不想子类继承的时候把这个宝贝改变了,这时候父类就用final修饰了这个宝贝,子类只能用不能覆盖并修改它。对子类继承父类的方法时,在内存中是如何分配的,这个应该时刻往节省内存的角度去考虑,所以方法覆盖的时候就出现不同的地方了。对于父类已有的非私有非final的方法,父类会对子类说,如果你不想修改我给你的方法,那么你继承过去了还得复制一份几乎一模一样的方法,还不如我把这个方法的使用权交给你,你到时候来找我用就行了,这样多省地方,(记住,子类继承父类,父类是不会死的,创建他的个体时,他也是存在的。)而如果子类想修改这些方法(即覆盖,写自己想要的内容),父类就告诉子类,你的权限必须是比我大的,才能覆盖,而且你覆盖了,这个方法就是你的了,跟我没有什么太大的关系,即如果子父类同时被实例化的前提下,这个方法在内方法区里是存在两份的。私有的和final的是很好想的,私有就只有父类的方法区中有,而final是父类的方法区中的这个方法给了子类一个使用的权利,子类可以使用,但是不能修改。这样解释这道题就好解释了:子类继承了父类的方法后,即子类并没有修改父类的方法,那么父类告诉子类,你来我的方法区用吧,子类有这个方法的使用权,但是这个方法得出的结果是什么样的,子类根本就不会知道,因为这个方法不在子类的方法区内。当子类看到自己要调用这个方法的指令后,它拿着父类给的权限去父类的方法区里调用这个方法,而这个方法正好也调用了父类的私有方法,父类说完了,我疏忽了,忘了我这个方法有调用我隐私内容的权利了,但为时已晚,子类看到结果也是大惊,但内心窃喜。而对于子类继承父类后,覆盖了父类的方法,子类调用这些方法当然是子类的方法结果。
多态让我蒙圈了很久,现在说说自己的一些关于多态的想法,子类有和父类一样的print方法,但是这两个是不同的,这个不叫覆盖,因为子类根本就不知道父类有这个方法,此时子类穿上了父类的衣服,调用print方法时,jvm编译时就告诉子类,你无权访问这个方法,说明父类引用变量指向子类对象的时候,调用方法的顺序是先到父类去查找的,而对于子类覆盖后的方法,jvm是知道子类穿着父类的衣服的,所以jvm就告诉子类,你没有能力调用父类的方法,因为你不具备这个功能,所以我就给你个标识,只要你穿着父类的衣服了,我就让你调用自己的衣服了。而对于成员属性,是描述父类和子类特征的,所以jvm再看到子类伪装成父类的时候,它已经有了父类的描述特殊了,即这个子类已经有了调用父类这些成员属性的能力了。写了好久,从五点爬起来,写到现在,楼主,给点分吧?

点评

如果能再回答的简明扼要些,就更好了,加油!  发表于 2012-7-29 15:22

评分

参与人数 2技术分 +2 黑马币 +6 收起 理由
职业规划-刘倩老师 + 2 赞一个!
创出一片辉煌 + 6 很给力!

查看全部评分

回复 使用道具 举报
因为父类中的print方法是private修饰的,是无法继承的所以不能重写的。私有一般都是通过间接访问的,被继承后父类还是存在的。
继承了父类的fun方法,this是代表s,但是父类的fun方法指定访问的是print,所以在子类中也会去访问相应重写的print方法,但是
子类中没有,所以就只能去访问父类了。
回复 使用道具 举报
吴立杰 发表于 2012-7-27 07:32
小结:这个程序的打印结果是
Person_test2
Person

楼主,偶不要金钱,偶要技术分哦
回复 使用道具 举报
吴立杰 发表于 2012-7-27 07:32
小结:这个程序的打印结果是
Person_test2
Person

嗯,我会努力的,谢啦
回复 使用道具 举报
本帖最后由 陆强强 于 2012-7-29 17:40 编辑

class Person{               
             void print(){//去掉private,打印的是Student,所以没有覆盖
                System.out.println("Person");
        }
        public void fun(){
                this.print();                //调用父类中的print方法
        }
}

class Student extends Person{                //定义子类
        void print(){
                System.out.println("Student");
        }
}

class OverrideDemo04{
        public static void main(String args[]){
                Student s = new Student();
                stu.fun();
        }
}
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马