J. Bloch在他的《Effective Java》一书中针对Java 6
版本提到了以下内容(第17条):
如果您认为必须允许从这样一个类进行继承,那么一个合理的方法是确保该类从不调用任何可重写方法,并记录此事实。换句话说,完全消除类对可重写方法的自我使用。
第18条:
如果您使用抽象类来定义类型,则给想要添加功能的程序员留下的唯一选择就是使用继承。结果得到的类比包装类更弱且更脆弱。
虽然接口不允许包含方法实现,但使用接口来定义类型并不妨碍您为程序员提供实现协助。
现在在Java 8
中,通过默认方法实现(使用接口中的其他方法)进行的接口继承是危险的。
例如:
public inteface MyInterface{
public void compute(Object o);
public default void computeAll(List<Object> oo){
for(Object o: oo)
compute(o); //self-use
}
}
据J. Bloch所说,尝试实现接口可能会带来一些问题,因为:
像这样覆盖方法(类似于J.Bloch提供的示例):
public class MyInterfaceCounter implements MyInterface{ private int count = 0; @Override public void compute(Object o) { count++; } @Override public void computeAll(List<Object> oo){ count += oo.size(); //Damn!! MyInterface.super.computeAll(oo); } }
客户端访问接口的内部,即他们必须了解默认实现。
在Java 8中应该怎么做?Effective Java的规则仍然适用吗?
此外,我们无法将默认方法声明为final
(就像我们可以为类所做的那样),这会使自我使用对覆盖者来说不太危险。