例1:
public class StaticTest {
public static int k = 0;
public static StaticTest t1 = new StaticTest("t1");
public static StaticTest t2 = new StaticTest("t2");
public static int i = print("i");
public static int n = 99;
public int j = print("j");
{
print("构造快");
}
{
print("静态块");
}
public StaticTest(String str) {
System.out.println((++k) + ":" + str + " i=" + i + " n=" + n);
++n;
++i;
}
public static int print(String str) {
System.out.println((++k) + ":" + str + " i=" + i + " n=" + n);
++i;
return ++n;
}
public static void main(String[] args) {
StaticTest t = new StaticTest("init");
}
}
结果:
1:j i=0 n=0
2:构造快 i=1 n=1
3:静态块 i=2 n=2
4:t1 i=3 n=3
5:j i=4 n=4
6:构造快 i=5 n=5
7:静态块 i=6 n=6
8:t2 i=7 n=7
9:i i=8 n=8
10:j i=9 n=99
11:构造快 i=10 n=100
12:静态块 i=11 n=101
13:init i=12 n=102
类加载顺序:
* 1.加载类的静态属性(非静态不管)
* 这里加载的是:public static int k = 0;
* 然后加载:public static StaticTest t1 = new StaticTest(“t1”);
* 因为此处进行了类的实例化所以
* 1.1加载类的非静态属性
* 这里是:public int j = print(“j”);
* 运行完这个方法接着
* 1.2顺序加载类中的非static代码块(static暂时不加载)
* 这里是:print(“构造快”);和print(“静态块”);
* 运行完接着
* 1.3加载类的构造方法
* 这里是:public StaticTest(String str)
* 运行完(一个静态属性的实例就完成了)
* 2.继续加载类的静态属性
* 这里加载的是:public static StaticTest t2 = new StaticTest(“t2”);
* 2.1重复(1.1-1.3)
* 3.继续加载类的静态属性
* 这里加载的是:public static int i = print(“i”);
* 运行完接着
* 4.继续加载类的静态属性
* 这里加载的是:public static int n = 99;
* 不管你n原来是多少现在为99
* 接着
* 5.(如果有static代码块,在这里先加载,这个里面没有所以加载主函数)加载主函数
* 这里加载的是:StaticTest t = new StaticTest(“init”);
* 因为此处进行了类的实例化所以
* 5.1
* 重复1.1-1.3
* 5.2
* 因为public static int print(String str)这个方法返回++n
* 所以n从99开始累
* 运行完OK了
例2:
public class test { //1.准备加载类
public static void main(String[] args) {
new test();
}
static int num = 4; //2.静态变量和静态代码块的加载顺序由编写先后决定
{
num += 3;
System.out.println("b"); //4.按照顺序加载匿名代码块和非静态变量
}
int a =5; //5.按照顺序加载匿名代码块和非静态变量
{
System.out.println("c"); //6.按照顺序加载匿名代码块和非静态变量
}
test() {
System.out.println("d"); //7.最后加载构造函数,完成对象的建立
}
static { //3.静态变量和静态代码块的加载顺序由编写先后决定
System.out.println("a");
}
static void run() // 静态方法,调用的时候才加载// 注意看,e没有加载
{
System.out.println("e");
}
}
一般顺序:静态块(静态变量)–>成员变量(匿名代码块)–>构造方法–>静态方法(调用的时候才加载)
例3:
public class Parent{
public static Print obj1 = new Print("1");
public Print obj2 = new Print("2");
public static Print obj3 = new Print("3");
static{
new Print("4");
}
public static Print obj4 = new Print("5");
public Print obj5 = new Print("6");
public Parent(){
new Print("7");
}
}
public class Child extends Parent{
static{
new Print("a");
}
public static Print obj1 = new Print("b");
public Print obj2 = new Print("c");
public Child (){
new Print("d");
}
public static Print obj3 = new Print("e");
public Print obj4 = new Print("f");
public static void main(String [] args){
Parent obj1 = new Child ();
Parent obj2 = new Child ();
}
}
执行main方法,程序输出顺序为: 1 3 4 5 a b e 2 6 7 c f d 2 6 7 c f d
如果有继承关系:
如果类还没有被加载:
1、先执行父类的静态代码块和静态变量初始化,并且静态代码块和静态变量的执行顺序只跟代码中出现的顺序有关。
2、执行子类的静态代码块和静态变量初始化。
3、执行父类的实例变量初始化
4、执行父类的构造函数
5、执行子类的实例变量初始化
6、执行子类的构造函数
如果类已经被加载:
则静态代码块和静态变量就不用重复执行,再创建类对象时,只执行与实例相关的变量初始化和构造方法。