如果我们在子类中启用覆盖,如何确保结构的正确性?
或者,换句话说,我们必须确保这一点吗?(如果不是,请给出强有力的理由。)
这是一个显示问题的简单示例:
我们的结构: anArrayList
只包含偶数。
库开发人员 Alice 编写了这个(正确的)类:
import java.util.ArrayList;
public class EvenArrayList {
private ArrayList<Integer> mArrayList = new ArrayList<Integer>();
public boolean isEven(int num) { return num % 2 == 0; }
public void addToList(int num) { if (isEven(num)) mArrayList.add(num); }
public void printList() { System.out.println(mArrayList); }
}
然而,邪恶的 Bob 用这个(错误的)子类覆盖了它:
public class EvilEvenArrayList extends EvenArrayList {
@Override
public boolean isEven(int num) { return true; }
}
使用时,Mandy 选择 Alice 的(正确的)类:
public class Main {
public static void main(String[] args) {
EvenArrayList eal = new EvenArrayList();
eal.addToList(1);
eal.addToList(2);
eal.addToList(3);
eal.addToList(4);
eal.addToList(5);
eal.printList(); // prints [2, 4]
}
}
使用时,Nancy 想要一些额外的功能,因此她选择了 Bob 的(错误的)子类:
public class Main {
public static void main(String[] args) {
EvilEvenArrayList eeal = new EvilEvenArrayList();
eeal.addToList(1);
eeal.addToList(2);
eeal.addToList(3);
((EvenArrayList) eeal).addToList(4);
((EvenArrayList) eeal).addToList(5);
eeal.printList(); // prints [1, 2, 3, 4, 5]
}
}
正如我们所看到的,即使 Nancy 明确地转换回 parent-class EvenArrayList
,也没有解决这个问题。
到目前为止,我想到了一个避免这种情况的解决方案(在 Alice 开发她的库时)。但是,这不是一个好的解决方案。
(1) 不调用其他方法:
public class EvenArrayList {
// ...
public boolean isEven(int num) { return num % 2 == 0; }
public void addToList(int num) { if (num % 2 == 0) mArrayList.add(num); }
// ...
}
(2) 或者,仅使用私有方法(因为它们不是继承的):
public class EvenArrayList {
// ...
public boolean isEven(int num) { return _isEven(num); }
private boolean _isEven(int num) { return num % 2 == 0; }
public void addToList(int num) { if (_isEven(num)) mArrayList.add(num); }
// ...
}
(3) 或者,仅使用 final 方法(因为它们不能被覆盖):
public class EvenArrayList {
// ...
public boolean isEven(int num) { return _isEven(num); }
public final boolean _isEven(int num) { return num % 2 == 0; }
public void addToList(int num) { if (_isEven(num)) mArrayList.add(num); }
// ...
}
这三种方法或多或少是相同的。
(1) 不太好,因为我们不能重用相同的代码块。
(2) 和 (3) 不太好,因为它们使类的复杂性几乎增加了一倍。此外,它为我们自己创造了一个“陷阱”,我们可能会错误地使用可覆盖的方法。
此外,(2) 和 (3) 引入了一点函数调用开销。
这个问题可能是
(1) 安全问题:
如果 Bob 故意错误地重写了某些方法,并诱使其他人使用他添加的(邪恶的)特征库,那么即使 Nancy 认为她使用的是 Alice 的方法版本,Nancy 仍然通过强制转换被黑客入侵。
(2) 和库开发人员的潜在陷阱:
即使我们同时扮演 Alice 和 Bob,子类中不正确的覆盖可能会破坏整个结构(甚至是 ArrayList),并且可能不容易找到错误的原因,因为它发生的位置与原因相去甚远(我们从来没有调用isEven()
使用)。
你有什么意见?请提供一些解决方案。非常感谢您的投入!!