黑马程序员技术交流社区

标题: 在子类中调用父类方法的问题 [打印本页]

作者: 李叶    时间: 2011-9-7 09:28
标题: 在子类中调用父类方法的问题
前两天在看银行视频的时候,把窗口类中的代码提取成子类的时候遇到了这样的问题
为了简单描述起见,我把问题简化成下面这段代码吧:[code=java]//Parent父类
public class Parent {
  //methodA方法
  public void methodA() {
    System.out.println("methodA of Parent!");  //打印一行语句
    methodB();                                 //调用methodB方法
  }

  //methodB方法
  public void methodB() {
    System.out.println("methodB of Parent!");  //打印一行语句
  }
}

//Child子类
public class Child extends Parent() {
  //覆盖了Parent类中的methodA方法
  public void methodA() {
    System.out.println("methodA of Child!");  //打印一行语句
    methodB();                                //调用methodB方法
  }

  //覆盖了Parent类中的methodB方法
  public void methodB() {
    System.out.println("methodB of Child!");  //打印一行语句
    super.methodA();                          //调用父类的methodA方法
  }
}

//Test测试类
public class Test {
  public static void main(String [] args) {
    Parent p = new Child();                   //父类引用指向子类对象
    p.methodA();                              //调用对象的methodA方法
  }
}[/code]这段代码运行的结果是:
methodA of Child!
methodB of Child!
methodA of Parent!
methodB of Child!
methodA of Parent!
methodB of Child!
...以下是死循环

这是因为在Child的methodB中调用的虽然是Parent中的methodA
但是在Parent中的methodA又调用回来Child中的的methodB了

那么,应当如何使Child调用Parent中的methodA的时候
使Parent的methodA调用Parent中的methodB呢?

也就是说如何修改才能使上面那段程序打印出以下的语句呢?
methodA of Child!
methodB of Child!
methodA of Parent!
methodB of Parent!
[ 本帖最后由 李叶 于 2011-09-07  09:33 编辑 ]
作者: 匿名    时间: 2011-9-7 10:01
标题: 回复 楼主 的帖子
将父类的methodB设为私有的。
就可以实现,
methodA of Child!
methodB of Child!
methodA of Parent!
methodB of Parent!
但是不知道是不是你想要的需求。
        // methodB方法
        private void methodB() {
                System.out.println("methodB of Parent!");// 打印一行语句
        }
作者: 李叶    时间: 2011-9-7 11:42
标题: 回复 沙发 的帖子
Thanks!需求就是这样的
子类不能覆盖父类中private的方法,这个给忘了……
看来还是得多写代码啊~
作者: 匿名    时间: 2011-9-7 11:43
也可以直接将MethodB 改名字,避免混淆
作者: 李叶    时间: 2011-9-7 11:45
标题: 回复 板凳 的帖子
恩,这里不需要用到多态,我就不应该按照覆盖的方式去写了呵呵,明白啦

不过如果Child并没有覆盖Parent的methodA的方法的话
如果想要达到上面的效果,应该怎么做呢?例如:[code=java]public class Parent {
  //methodA方法
  public void methodA() {
    System.out.println("methodA Executed!");   //打印一行语句
    methodB();                                 //调用methodB方法
  }

  //methodB方法
  public void methodB() {
    System.out.println("methodB of Parent!");  //打印一行语句
  }
}

//Child子类
public class Child extends Parent() {
  //只覆盖了Parent类中的methodB方法
  public void methodB() {
    System.out.println("methodB of Child!");  //打印一行语句
    super.methodA();                          //调用父类的methodA方法
  }
}

//Test测试类
public class Test {
  public static void main(String [] args) {
    Parent p = new Child();                   //父类引用指向子类对象
    p.methodA();                              //调用对象的methodA方法
  }
}[/code]如果是将methodB改为private的话,只能打印出来
methodA Executed!
methodB of Parent!
也就是说调用methodA方法时,只能调用parent中的methodB方法,而不会去调用child中的methodB方法

如何修改这段语句,才能使上面那段程序打印出以下的语句呢?
methodA Executed!
methodB of Child!
methodA Executed!
methodB of Parent!

注:在这里我的代码结构应该是有问题的,我想达到的目的只是:
假设方法A中有100行代码,其中有90行代码是通用的,只有10行代码是不一样的
所以,我就想将这10行代码提取出来,写成一个方法B
并且,我还想要使方法A通过调用同一个方法B,来执行不同的代码
所以,我就定义了多个不同的子类,并在子类中实现了这个方法B
然后下一步应该怎么写呢?

再注:描述完了问题以后,我发现这似乎是接口回调的应用……
如果使用接口回调来实现上面的功能的话,应当怎么做呢?
[ 本帖最后由 李叶 于 2011-09-07  12:21 编辑 ]
作者: 李治    时间: 2011-9-7 12:36
标题: 回复 报纸 的帖子
我们首先分析,结果:
methodA Executed!
methodB of Child!
methodA Executed!
methodB of Child!
调用的是methodA(27行),却分别执行了子类和父类的methodB(methodB of Child!和methodB of Child!)。这个肯定要在子类中重写methodB方法。
然后,在执行子类的methodB之前,又要执行了父类的methodA,这就形成了递归。看似无法实现了。
但是如果只想得到结果不是没有办法的,可以用一个变量,来控制递归的深度,从而打印出需要的代码,
这是我分析的出的结果,也许其他人有更好的办法。
  1. class Parent {
  2.         protected static int counter = 0;

  3.         // methodA方法
  4.         public void methodA() {
  5.                 System.out.println("methodA Executed!"); // 打印一行语句
  6.                 // 只让methodA递归两次.
  7.                 if (counter == 2) {
  8.                         return;
  9.                 }
  10.                 counter++;
  11.                 methodB(); // 调用methodB方法
  12.         }

  13.         // methodB方法
  14.         public void methodB() {
  15.                 System.out.println("methodB of Parent!");// 打印一行语句
  16.         }
  17. }

  18. // Child子类
  19. class Child extends Parent {
  20.         // 只覆盖了Parent类中的methodB方法
  21.         public void methodB() {
  22.                 // 第二次递归,就调用父类的methodB.
  23.                 if (counter == 2) {
  24.                         super.methodB();
  25.                         return;
  26.                 }
  27.                 System.out.println("methodB of Child!");// 打印一行语句
  28.                 super.methodA();// 调用父类的methodA方法
  29.         }
  30. }

  31. // Test测试类
  32. public class Test{
  33.         public static void main(String[] args) {
  34.                 Parent p = new Child(); // 父类引用指向子类对象
  35.                 p.methodA(); // 调用对象的methodA方法
  36.         }
  37. }
复制代码
[ 本帖最后由 李治 于 2011-09-07  12:39 编辑 ]
作者: 李叶    时间: 2011-9-7 13:46
标题: 回复 地板 的帖子
呵呵,谢谢你这么耐心的回答!这个问题我已经想明白了
在执行子类的methodB之前,又要执行了父类的methodA,这就形成了递归。

这句话非常重要~也就是说,如果想要达到我的目标的话,这段代码的设计模式的确是存在着很大问题的
这一中午我一直在想这个问题,在这里给出我的修改后的代码吧![code=java]//新定义的一个类,该类仅提供methodA方法
class Service {
  //methodA方法,该方法可以接受一个Parent类型的参数
  public methodA(Parent p) {
    System.out.println("methodA Executed!");    //执行通用代码
    p.methodB();                                //执行Parent里面的methodB方法         
  }      
}

//新定义的一个接口,该接口仅提供methodB方法
interface Parent (
  public void methodB();
}

//Parent接口的第一种实现
class ChildA implements Parent {
  //methodB方法的实现,实际上就等同于之前例子中的Parent类中methodB方法的实现
  public void methodB() {
    System.out.println("methodB of Parent!");
  }
}

//Parent接口的第二种实现
class ChildB implements Parent {
  //methodB方法的实现,实际上就等同于之前例子中的Child类中methodB方法的实现
  public void methodB() {
    System.out.println("methodB of Child!");

    //调用Service类中的methodA方法,就等同于之前例子中调用Parent类中的methodA方法
    //在这里传入一个ChildA的对象,就等同于之前的例子中让Parent类的methodA方法调用Parent中的methodB方法
    Service s = new Service();
    Parent a = new ChildA();
    s.methodA(a);
  }
}

//测试类
public class Test {
  public static void main(String [] args) {
    Service s = new Service();
     Parent p = new ChildB();      //创建一个ChildB对象,也就相当于之前的Child对象

    s.methodA(p);                 //将实现了ChildB对象传入methodA方法中执行
  }
}[/code]这样的话,就可以打印出
methodA Executed!
methodB of Child!
methodA Executed!
methodB of Parent!
这四行结果了

也就是说,我的设计上出现的根本问题是:
这两个类的关系不应该是继承,而应当是同一个接口的实现类
此外,由于只有methodB不同,所以应当仅在接口中提供methodB的不同实现,而methodA不应当在接口中定义

再次感谢李治童鞋~!
[ 本帖最后由 李叶 于 2011-09-07  14:00 编辑 ]
作者: 匿名    时间: 2011-9-7 14:14
标题: 回复 7 # 的帖子
呵呵,客气了.客气了.能对你有帮助就好,相互进步嘛.
作者: 匿名    时间: 2011-9-7 14:40
李叶第一个代码
我改成private
两个类的public去掉了
删了16行的括号
其他没问题啊
能打印出
methodA of Child!
methodB of Child!
methodA of Parent!
methodB of Parent!
作者: 匿名    时间: 2011-9-7 16:05
标题: 回复 9 # 的帖子
嗯,是可以打印出这几行语句,不过那样的话就必须要在Child类里面重写methodA方法里面的代码了,也就是说methodA里面的代码不能重用~所以才会有下面的问题的~




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