本篇文章是看《effective java》第17条有感,在其基础上还是有所扩展。本篇文章主要探究的是:在类继承之后,创建子类对象,对父类构造器的调用,以及类初始化的顺序(即父类域的初始化,子类域的初始化)。对于这样的分析,别什么理论不理论,我的解决方案就是先编个程看看,实际情况是什么样,要是和自己理解的不一样,再查资料,补充自己的理论体系。所以不废话了,看代码!
class SuperClass{
public static String superStaticField="父类===静态域";
public String superField="父类===变量";
static{
System.out.println(superStaticField);
System.out.println("父类===静态初始化块");
}
{
System.out.println(superField);
System.out.println("父类===初始化块");
}
public SuperClass(){
System.out.println("父类构造器");
}
}
public class SubClass extends SuperClass {
public static String subStaticField="子类===静态域";
public String subField="子类===变量";
static{
System.out.println(subStaticField);
System.out.println("子类===静态初始化块");
}
{
System.out.println(subField);
System.out.println("子类===初始化块");
}
public SubClass(){
System.out.println("子类构造器");
}
public static void main(String[] args){
System.out.println("----------------");
new SubClass();
}
}
输出的结果是:
父类===静态域
父类===静态初始化块
子类===静态域
子类===静态初始化块
----------------
父类===变量
父类===初始化块
父类构造器
子类===变量
子类===初始化块
子类构造器
从代码到输出结果我们可以看到一清二楚,我们实现了类的继承,那首先要先有个父类,所以java做的也对,就是先初始化父类,先将父类的.class文件加载进来,有了父类然后再加载子类。由于静态域是类固有的域,在没有对象之前就已经存在,是在编译好后就已存在的域,所以在编译好后,父类的静态域和子类的静态域都已经初始化好了,所以先打印的就是静态域。然后开始类的一般变量的初始化,当然首先是从父类开始的,这也非常理解,只有在父类的所有情况全部稳定之后,子类才能进行状态的初始化,要不然子类就没法用父类的东西了!
然后我们再做个试验,把main方法里的所有语句都注释掉是什么情况,你会看到只有分割线(--------------)上面的输出了。这也刚好证实了,类的静态域是在编译时候就已经初始化存在了的,是与类共生的,即使是没有创建对象也能够使用! 这有相当的好处,这也是《effective java》里讲的另一条,就是静态工厂的说法,在这里就不展开了。
下面我们从这个例子中衍生出其他的问题,其实也是继承出现的问题,为了突出这个问题,下面让我把代码简化。
import java.util.*;;
class Super{
public Super(){
overrideMe();
}
public void overrideMe(){
}
}
public class Sub extends Super{
private final Date date;
Sub(){
date=new Date();
}
public void overrideMe(){
System.out.println(date);
}
public static void main(String[] args){
System.out.println("------输出:");
Sub sub=new Sub();
sub.overrideMe();
}
}
这个输出是什么呐?
-------输出:
null
Fri Mar 27 15:59:56 CST 2015
第一个输出是null,原因就是从在加载父类构造器的时候,父类构造器调用了overrideMe()方法,此方法在子类中被覆盖,所以在调用的时候就调动了还没有初始化的date,当然就是null了。这个问题其实分析起来并不难,主要讨论的就是我们继承java中的工具类的时候,有没有考虑到会出现这种情况,以及如何避免这种情况的发生。《effective java》的做法是尽量使用组合的形式来扩展我们的类!