/**
* @(#)TestJava.java 2008-2-22
*
* Copyright 2007 GeneralData, Inc. All rights reserved.
*/
package
com.bbebfe;
/**

* 这个类测试父类和子类的构造时机

* 父类中有一个(抽象)方法prt();

* 子类(实现)覆盖了这个方法,并打印"in child" + i,i是

* 子类中定义的一个成员字段,设定初值为10。

*

* 在父类的构造中调用prt(),

* 如果能够调用成功,说明子类对象在子类的构造方法执行前

* 已经在内存中构造好了(因为父类的构造方法会在子类的构造

* 方法前执行),因为如果子类对象没有在内存中存在,则

* 不可能执行打印,更不能打印成员字段i。

*

* 最终的执行结果是成功打印"in child 0",说明能够执行打印,

* 说明子类对象的内存已经分配。

* 但i的值打印为0,说明内存虽然已经分配,但成员字段尚未执行显示初始化,

* 默认初始化为0。

* 在Child的构造中打印i的值为10,说明成员字段的显示初始化在内存分配

* 和构造体之间进行。

*

* 因此可以看出一个Java对象的具体构造过程(不包含静态结构):

* 1. 父类对象内存分配

* 2. 父类字段默认初始化

* 3. 子类对象内存分配

* 4. 子类字段默认初始化

* 5. 进入父类构造-> 父类成员显示初始化(定义字段时设置的字段初值)

*         -> 执行父类构造体(此时可以调用抽象方法,所有父类字段已初始

*             化完毕,但子类字段尚未进行显示初始化)

* 6. 进入子类构造-> 子类成员显示初始化(定义字段时设置的字段初值)

*         -> 执行子类构造体(此时所有字段已经显示初始化)

*

* 因此,父类的构造中可以调用抽象方法(子类实现),但最好

* 不要这样做,因为子类对象仅仅分配了内存和默认初始化,还没有

* 进行显示初始化。

* @project TestJava
*
@author
chenhao
*
@version
1.0.0, 2008-2-22
*/
public
class
TestJava {
public
static
void
main(String[] args) {
Child c
=
new
Child();
}
}
class
Child
extends
Father
{
int
i
=
10
;
/**

* 这个构造方法是没有必要写的,因为默认构造

* 肯定是按这个顺序执行的。但为了表示明确的

* 目的,因此把这个默认构造写出来

*
*/
public
Child() {
super
();
System.out.println(i);
}
@Override
public
void
prt() {
System.out.println(
"
in child i =
"
+
i
+
"
k =
"
+
k);
}
}
abstract
class
Father
{
protected
int
k
=
5
;
public
Father() {
prt();
}
public
void
prt() {
System.out.println(
"
in Father k =
"
+
k);    }}