近日在工程中发现了这么一个bug:妄自以为子类的域可以像方法一样覆盖父类的域或者方法。
具体的情景可以抽象为以下:试图在父类中定义一个域(非private)并赋予初始值,各个子类算法默认情况下使用该域的默认初始值,在必要的情况下想覆盖该域重新定义该值,于是有了这样的代码:
public abstract class AbstractAlogrithm {
protected int nTimeSpan = 12;
protected void printTimeSpan(){
System.out.println(nTimeSpan);
}
}
public class BAlogrithm extends AbstractAlogrithm {
}
public class CAlogrithm extends AbstractAlogrithm {
protected int nTimeSpan = 24;
}
public static void main(String[] args) {
AbstractAlogrithm obj = new BAlogrithm();
obj.printTimeSpan(); //12
obj = new CAlogrithm();
obj.printTimeSpan(); //12
CAlogrithm obja = new CAlogrithm();
obja.printTimeSpan(); //12
}
域:不并具备多态性
以为后两者的输出应该是24,实际并非如此;java编程思想已经很好的诠释:
一旦你了解了多态机制,可能就会开始认为所有的事物都是可以多态地发生。然而只有普通的方法调用可以是多态的。
实际上CAlogrithm.nTimeSpan和AbstractAlogrithm.nTimeSpan是相互独立的,他们有不同的存储空间;即使在obja中试图打印nTimeSpan,但是你调用的是基类的方法,那么他只能访问到基类的nTimeSpan,自然无法给你想要的值。
某些时候,你可能试图通过将父类强制转型成子类引用,试图访问子类的同名称域,但是任何域的访问都是编译器操作,因此这不是多态的。
静态方法:多态是运行时的行为,而静态方法是编译期就确定的,自然无法实现多态;
那么如何实现我们的意图了,去往罗马的路当然不止一种,以下便是一种:
public class CAlogrithm extends AbstractAlogrithm {
//protected int nTimeSpan = 24;
public CAlogrithm() {
nTimeSpan = 24;
}
}
还有一些demo,可以参见java编程思想第四版中文,第8.2.5章节:缺陷:域与静态方法