问:下面这段父子类的代码有什么问题?

父类:提供两个方法add和addAll,将输入数字添加到内部数组中。

public class Base {

  private static final int MAX_NUM = 1000;
  private int[] arr = new int[MAX_NUM];
  private int count;

  public void add(int number) {
    if (count < MAX_NUM) {
      arr[count++] = number;
    }
  }

  public void addAll(int[] numbers) {
    for (int num : numbers) {
      add(num);
    }
  }
}

子类:重写了基类的add和addAll方法,在添加数字的同时汇总数字,存储数字的和到实例变量sum中,并提供了方法getSum获取sum的值。

public class Child extends Base {

  private long sum;

  @Override
  public void add(int number) {
    super.add(number);
    sum += number;
  }

  @Override
  public void addAll(int[] numbers) {
    super.addAll(numbers);
    for (int i = 0; i < numbers.length; i++) {
      sum += numbers[i];
    }
  }

  public long getSum() {
    return sum;
  }
}

后面有答案和解析

答案:子类addAll函数的运行结果错误。

比如下面程序,我们会发现输出的结果是错的:正确的结果应该是6但实际输出12!

public static void main(String[] args) {
  Child c = new Child();
  c.addAll(new int[] { 1, 2, 3 });
  System.out.println(c.getSum());
}

原因:同一个数字被汇总了两次。子类的addAll方法首先调用了父类的add-All方法,而父类的addAll方法通过add方法添加,由于动态绑定,子类的add方法会执行,子类的add也会做汇总操作。

从这个例子可以看出,如果子类不知道基类方法的实现细节,它就不能正确地进行扩展。

修正:可以修改子类addAll方法,不再重复计数

@Override
public void addAll(int[] numbers) {
  super.addAll(numbers);
}

但是,当基类addAll方法不想不调用add方法,而是直接往数组中添加数字后(这是Base类的实现细节),上述mian的运行结果又变错误了:正确的结果应该是6,但实际输出0!

public void addAll(int[] numbers) {
  for (int num : numbers) {
    if (count < MAX_NUM) {
      arr[count++] = num;
    }
  }
}

很明显,这个例子中,子类和父类之间是存在细节依赖的,子类扩展父类,仅仅知道父类能做什么是不够的,还需要知道父类是怎么做的(子类需要知道父类的可重写方法之间的依赖关系);而父类的实现细节也不能随意修改,否则可能影响子类(父类不能随意改变可重写方法之间的依赖关系)。

#java原理#
Java面试专辑 文章被收录于专栏

帮您起飞,助您着陆心仪大厂。

全部评论

相关推荐

04-14 16:56
门头沟学院 Java
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务