(5);
}
public class StaticInitialization {
? ? public static void main(String[] args) {
? ? ? ? System.out.println("Creating new Cupboard() in main");
? ? ? ? new Cupboard();
? ? ? ? System.out.println("Creating new Cupboard() in main");
? ? ? ? new Cupboard();
? ? ? ? t2.f2(1);
? ? ? ? t3.f3(1);
? ? }
? ? static Table t2 = new Table();
? ? static Cupboard t3 = new Cupboard();
}
【运行结果】:
Bowl(1)
Bowl(2)
Table()
f(1)
Bowl(4)
Bowl(5)
Bowl(3)
Cupboard()
f(2)
Creating new Cupboard() in main
Bowl(3)
Cupboard()
f(2)
Creating new Cupboard() in main
Bowl(3)
Cupboard()
f(2)
f2(1)
f3(1)
静态代码块
Java允许将其他static初始化工作划分到类内一个特殊的代码块中,这种代码块的形式为static关键字,后面跟着一个方法主体,称为静态代码块。静态代码块只有在第一次生成那个类的对象或首次访问属于那个类的static成员时执行。例如:
class Person {
? ? Person(int age) {
? ? ? ? System.out.println("Person(" + age + ")");
? ? }
? ? void f(int age) {
? ? ? ? System.out.println("f(" + age + ")");
? ? }
}
class Persons {
? ? static Person p1;
? ? static Person p2;
? ? static {
? ? ? ? p1 = new Person(1);
? ? ? ? p2 = new Person(2);
? ? }
? ? Persons() {
? ? ? ? System.out.println("Persons()");
? ? }
}
public class ExplicitStatic {
? ? public static void main(String[] args) {
? ? ? ? System.out.println("Inside main()");
? ? ? ? Persons.p1.f(18);//1
? ? }
? ? static Persons x = new Persons();//2
? ? static Persons y = new Persons();//2
}
在标记为1的行内访问static对象p1的时候,或在行1被注释而行2未被注释是,用于Persons的static初始化模块就会运行。若1和2都被注释掉,则用于Persons的静态代码块不会执行。
静态属性和静态代码块执行的先后顺序
class Person {
? ? Person(int age) {
? ? ? ? System.out.println("Person("+age+")");
? ? }
}
class Persons {
? ? static Person p = new Person(2); // 1
? ? static {
? ? ? ? p = new Person(3);
? ? }
? ? static Person p = new Person(2); // 2
}
public class CompStaticInit {
? ? public static void main(String[] args) {
? ? }
? ? static Persons x = new Persons();
}
根据注释1保留2,注释2保留1的结果分析可知,静态属性和静态代码块的执行顺序取决于编码的顺序。谁在前面就先执行谁。
非静态属性的初始化
class Animal {
? ? Animal(int age) {
? ? ? ? System.out.println("Animal(" + age + ")");
? ? }
? ? void f(int age) {
? ? ? ? System.out.println("f(" + age + ")");
? ? }
}
public class NotStaticInit {
? ? Animal a1;
? ? Animal a2;
? ? {
? ? ? ? a1 = new Animal(1);
? ? ? ? a2 = new Animal(2);
? ? ? ? System.out.println("a1 & a2 initialized");
? ? }
? ? NotStaticInit() {
? ? ? ? System.out.println("NotStaticInit");
? ? }
? ? public static void main(String[] args) {
? ? ? ? System.out.println("Inside main()");
? ? ? ? NotStaticInit x = new NotStaticInit();
? ? }
}
类似于静态代码块,匿名代码块与非静态属性的初始化顺序取决于编码顺序。
继承中的对象初始化过程
class Insect {
? ? int i = 1;
? ? int j;
? ? Insect() {
? ? ? ? prt("i = " + i + ", j = " + j);
? ? ? ? j = 2;
? ? }
? ? static int x1 = prt("static Insect.x1 initialized");
? ? static int prt(String s) {
? ? ? ? System.out.println(s);
? ? ? ? return 3;
? ? }
}
public class Beetle extends Insect {
? ? int k = prt("Beeklt.k initialized");
? ? Beetle() {
? ? ? ? prt("k = " + k);
? ? ? ? prt("j = " + j);
? ? }
? ? static int x2 = prt("static Bootle.x2 initialized");
? ? static int prt(String s) {
? ? ? ? System.out.println(s);
? ? ? ? return 4;
? ? }
? ? public static void main(String[] args) {
? ? ? ? prt("Beetle constructor");
? ? ? ? Beetle b = new Beetle();
? ? }
}
【运行结果】:
static Insect.x1 initialized
static Bootle.x2 initialized
Beetle constructor
i = 1, j = 0
Beeklt.k initialized
k = 4
j = 2
对Beetle运行Java时,发生的第一件事情是装载程序到外面找到那个类。在装载过程中,装载程序发现一个基础类,所以随之将其载入。无论是否生成基础类的对象,这一过程都将执行。如果基础类含有另一个基础类,则另一个基础类随即也会载入,以此类推。接下来就在根基础类中执行static初始化,再在下一个衍生类中执行,以此类推。这是因为衍生类的初始化可能要依赖于对基础类成员的初始化。
当类都装载完毕,就能创建对象。首先,这个对象中的所有基本数据类型都会设置成为他们的默认值,对象句柄设为null。然后执行基础类的构建器。这种情况是自动完成的(衍生类的构造函数中默认调用了super(),也可以通过super指定基类的构建器)。基础类构建器完成后,衍生类实例变量就会按本来的顺序得到初始化,然后执行构建器的剩余的主体