重点记忆:构造代码块(普通代码块)是随着构造器的执行而执行。当执行构造器的时候,如果有构造代码块,会先执行构造代码块,然后再执行构造器。
类中的实例成员,相当于构造代码块。也就是说,构造代码块执行的时候,也会执行实例成员。
类中的静态成员,相当于静态代码块,也就是说,静态代码块执行的时候,也会执行静态成员。
类加载有四种情况:调构造器,Class.formName(),调静态属性,调静态方法。后面两个都可以省略类名。
静态代码块在整个程序运行期间只执行一次。代码块是每创建一个实例就会执行一次。
如果有多个静态代码块,那么按顺序执行。
静态的东西,类加载时就会分配空间,但是有可能没有赋值,但是此时会有默认值。
例题讲解
public class AppTest {
public static void main(String[] args) {
f1();
}
static AppTest appTest = new AppTest();
static {
System.out.println("1");
}
{
System.out.println("2");
}
AppTest(){
System.out.println("3");
System.out.println("a="+a+",b="+b);
}
public static void f1(){
System.out.println("4");
}
int a = f2();
static int b = f3();
public int f2(){
System.out.println("x");
return 5;
}
public static int f3(){
System.out.println("y");
return 6;
}
}
当调用main方法中调用f1()
的时候,这个其实相当于是AppTest.f1()
,所以此时引发了类加载,此时会执行静态代码块,当有多个静态代码块的时候,按顺序执行。所以执行static AppTest appTest = new AppTest();
,这里开始创建实例,因为构造代码块随着构造器的执行而执行,即执行构造方法之前要执行构造代码块,所以紧接着执行{ System.out.println("2"); }
,执行完之后,因为类中的实例成员,相当于构造代码块。也就是说,构造代码块执行的时候,也会执行实例成员。所以紧接着执行int a = f2();
,此时调用f2()
,执行public int f2(){ System.out.println("x"); return 5; }
,此时输出x,然后a的值为5
。接着执行构造方法,AppTest(){ System.out.println("3"); System.out.println("a="+a+",b="+b); }
,但是这里a是有值的,b没有值,因为静态的东西,在加载的时候就会分配空间,只有当你执行过显示赋值之后,才会将设置的值赋值给该静态变量,此时显然还没有执行到给b赋值的代码,因为分配空间的时候,会给默认值,int的默认值是0,所以b的值是0。
此时第一个静态代码块执行完毕,接着执行第二个静态代码块static { System.out.println("1"); }
,然后第三个静态代码块,static int b = f3();
,此时调用f3()
,执行public static int f3(){ System.out.println("y"); return 6; }
,执行完f3()
之后,b才被显示赋值,值为6,然后调用f1()方法。
所以最后的结果为:2 x 3 a=5,b=0 1 y 4
如果main方法中再一次调用f1(),此时只会输出4,即main()方法中调用两次f1(),输出的结果为2 x 3 a=5,b=0 1 y 4 4
,因为类只会被加载一次,静态的东西,也只会执行一次,就是在类加载的时候执行。
但是如果你创建实例的话,构造代码块会在调用构造器之前执行,创建多少次实例,构造代码块就执行几次。