Java代码的执行顺序
后面大量的涉及到了static,我曾经写过一篇static的博客,可以看一眼
我上次写了static的加载顺序,没看过的可以进去看一眼
---------------------分割线-----------------------------------------
我们先来看几个demo,难度从简单到难
demo1
java
public class Demo1 {
public Demo1(String aa) {
System.out.println("======" + aa);
}
static {
System.out.println("11");
}
public static Demo1 demo1 = new Demo1("+++++");
}
class A {// 内部类
public static void main(String[] args) {
Demo1 demo1 = new Demo1("------");
}
}
代码的执行顺序是?
运行结果
静态代码块和静态变量同属于静态部分,都是最优先加载
demo2
java
public class Demo2 extends Base {
static {
System.out.println("test static");
}
public Demo2() {
System.out.println("test construct");
}
{
System.out.println("test 代码块");
}
public static void main(String[] args) {
Demo2 demo2 = new Demo2();
}
}
class Base {
public Base() {
System.out.println("base construct");
}
static {
System.out.println("base static");
}
{
System.out.println("base 代码块");
}
}
代码的执行顺序是?
运行结果
我们发现
- 静态代码块最优先执行,但是父类的静态代码块比子类的静态代码块更优先
- 然后是普通代码块,依然是父类先执行
- 最后是构造器,同上
原因:
- 双亲委派机制,让类加载器classLoader加载类时,优先加载父类
- 普通代码块只有创建对象后才能进入堆内存,才能执行
- 子类执行构造方法时,会先去执行父类的构造方法
双亲委派机制很复杂,这里只是简单的概述,大致意思是,保证类只会加载一次 + 父类优先加载
总结:
①Demo1类加载时,先去扫描父类是否存在,Base存在,然后优先加载父类,所以父类的静态代码块先执行
②两个类加载到方法区之后,开始执行main方法。
③main方法通过Demo1类的无参构造创建了一个Demo1类的对象,执行Demo1的构造方法之前,会先去执行父类的无参构造,创建了一个父类的匿名对象,放入堆中
④只要在堆中开辟了空间,代码块就会执行,随后创造对象。所以父类的代码块先执行,然后执行父类的构造方法;子类的代码块靠后执行,然后是构造方法
⑤构造方法执行完毕之后,最后才会轮到main方法中,对象调用的其他非静态方法
demo3(非常难)
java
public class Demo3 {
private static int k = 1;
private static Demo3 t1 = new Demo3("t1");
private static Demo3 t2 = new Demo3("t2");
private static int i = print("i");
private static int n = 99;
public Demo3(String str) {
System.out.println((k++) + ":" + str + " i=" + i + " n=" + n);
++i;
++n;
}
static {
print("静态块");
n = 100;
}
public static int print(String str) {
System.out.println((k++) + ":" + str + " i=" + i + " n=" + n);
++n;
return ++i;
}
public static void main(String[] args) {
}
}
代码的执行顺序是?