问:下面这段父子类的代码有什么问题?
父类:提供两个方法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面试专辑 文章被收录于专栏
帮您起飞,助您着陆心仪大厂。
查看15道真题和解析