Java代码执行顺序

  1. static修饰的方法或者代码块只在类加载时执行,类是用类加载器来读取的,类加载器是带有一个缓存区的,它会把读取到的类缓存起来,所以在一次虚拟机运行期间,一个类只会被加载一次。因此,静态代码块优先于其他代码执行且只会运行一次,静态方法优先于其他代码执行,但是静态代码块、静态方法等是根据上下顺序执行。(即静态代码块再上则优先执行静态代码块、静态方法在上则优先执行静态方法)
  2. 静态代码后是主方法开始执行,与静态代码块执行一次不同,若是主方法中不管通过什么再次调用了静态方法,静态方法仍可执行
  3. 若程序中存在普通代码块和构造方法,则调用构造方法之前会先执行普通代码块再执行构造方法,最后执行构造方法中的普通方法或者主程序后的普通方法
  4. 若是存在父子类关系,则父类中的静态代码优先于子类中的静态代码(父类加载优先于子类加载),若存在子类构造方法调用父类的构造方法,则先执行父类的构造方法再执行子类的构造方法。

总结:静态代码 -> main方法 -> 普通代码块 -> 构造方法 -> 普通方法

1.据下面的代码,可以来看看Java代码的执行顺序

public class Test06 {
    public static Test06 si = new Test06();
    public Test06() {
        System.out.println("constructor");
        m1();
        System.out.println(si);
    }
    public static void m1() {
        System.out.println("static method");
    }
    { System.out.println("instance block"); }
    static { System.out.println("static"); }
    public static void main(String[] args) {
        System.out.println("main start");
        new Test06();
        System.out.println("main end");
    }
}

根据之前所述的Java代码运行顺序得到,在主方法调用之前先会进行类加载,静态的代码块或是方法会按照顺序执行,因此顺序为:

  1. 加载了一个静态的Test06类,并且调用了构造方法(new Test06),所以先加载普通代码块,输出"instance block"
  2. 进入到构造方法中,输出"constructor"
  3. 按顺序执行m1()方法,输出"static method"
  4. 输出si的地址值,此时并没有实例化一个对象,因此si的地址值为null
  5. 接着是静态代码块"instance block",但注意因为是类加载静态的变量、方法、代码块只加载一次,而之间已经加载过了静态m1()方法,因此这里会跳过静态的m1()方法去加载静态的代码块
  6. 类加载完毕后,主方法开始执行,因此先输出"main start"
  7. 然后是实例化了一个对象new Test06(); 这时会去调用Test06()构造方法,因此又执行一次普通代码块(优先于构造方法执行)输出"instance block"
  8. 然后进入构造方法中按顺序执行,输出"constructor"
  9. 调用m1()方法,输出"static method"
  10. 输出si的地址值
  11. 最后输出"main end",程序停止运行
//这是上述代码的运行结果
instance block
constructor
static method
null
static
main start
instance block
constructor
static method
com.zzxx.test.Test06@4554617c
main end

2.让我们再来看看这个

class Test1 {
    public Test1() {
        System.out.println("Test1");
    }
    {
        System.out.println("I'm Test1 class");
    }
    static {
        System.out.println("static Test1");
    }
}
public class Test2 extends Test1 {
    public Test2() {
        System.out.println("Test2");
    }
    {
        System.out.println("I'm Test2 class");
    }
    static {
        System.out.println("static Test2");
    }
    public static void main(String[] args) {
        new Test2();
    }
}

根据之前所述的Java运行代码,来看看顺序

  1. 先进行类加载,由于父类优先于子类加载,因此先输出"static Test1"
  2. 接着加载子类输出static Test2
  3. 之后执行主方法,new Test2();调用Test2()构造方法,注意,此时是子类的无参构造方法,会默认有一个super()方法,因此在子类中其实的代码是这样的
public Test2() {
    super();
    System.out.println("Test2");
}

由此,先回去调用父类的构造方法,在这之前先执行父类中的普通代码块,输出"I’m Test1 class"
4. 调用Test1()输出"Test1"
5. 返回到子类中,优先于子类的构造方法先执行子类的普通代码块,输出"I’m Test2 class"
6. 然后执行Test2(),输出"Test2"

//用Java程序执行上述代码结果为
static Test1
static Test2
I'm Test1 class
Test1
I'm Test2 class
Test2