一、在一個類中的執行順序:
public class test { //1.第一步,準備加載類
public static void main(String[] args) {
new test(); //4.第四步,new一個類,但在new之前要處理匿名代碼塊
}
static int num = 4; //2.第二步,靜態變量和靜態代碼塊的加載順序由編寫先後決定
{
num += 3;
System.out.println("b"); //5.第五步,按照順序加載匿名代碼塊,代碼塊中有打印
}
int a = 5; //6.第六步,按照順序加載變量
{ // 成員變量第三個
System.out.println("c"); //7.第七步,按照順序打印c
}
test() { // 類的構造函數,第四個加載
System.out.println("d"); //8.第八步,最後加載構造函數,完成對象的建立
}
static { // 3.第三步,靜態塊,然後執行靜態代碼塊,因爲有輸出,故打印a
System.out.println("a");
}
static void run() // 靜態方法,調用的時候才加載// 注意看,e沒有加載
{
System.out.println("e");
}
}
小結:
一般順序:靜態塊(靜態變量)——>成員變量——>構造方法——>靜態方法
1、靜態代碼塊(只加載一次)
2、構造方法(創建一個實例就加載一次)
3、靜態方法需要調用纔會執行,所以最後結果沒有e
二、當存在繼承關係的時候:
public class ClassA {
private static int number = getNumber();
static{
System.out.println("運行ClassA的靜態塊");
}
{
System.out.println("運行ClassA的非靜態塊");
}
public ClassA() {
System.out.println("運行ClassA的構造方法");
}
public static int getNumber() {
System.out.println("運行ClassA靜態變量number");
return 0;
}
public static void getDate() {
System.out.println("運行ClassA靜態方法getDate");
}
}
class ClassB extends ClassA{
private static int number = getNumber();
static{
System.out.println("運行ClassB的靜態塊");
}
{
System.out.println("運行ClassB的非靜態塊");
}
public ClassB() {
System.out.println("運行ClassB的構造方法");
}
public static int getNumber() {
System.out.println("運行ClassB靜態變量number");
return 0;
}
public static void getDate() {
System.out.println("運行ClassB靜態方法getDate");
}
}
package com.example;
public class Main {
public static void main(String[] args) {
ClassB test = new ClassB();
}
}
執行結果:
運行ClassA靜態變量number
運行ClassA的靜態塊
運行ClassB靜態變量number
運行ClassB的靜態塊
運行ClassA的非靜態塊
運行ClassA的構造方法
運行ClassB的非靜態塊
運行ClassB的構造方法
小結:
如果類還沒有被加載:
1、先執行父類的靜態代碼塊和靜態變量初始化,並且靜態代碼塊和靜態變量的執行順序只跟代碼中出現的順序有關。
2、執行子類的靜態代碼塊和靜態變量初始化。
3、執行父類的實例變量初始化
4、執行父類的構造函數
5、執行子類的實例變量初始化
6、執行子類的構造函數
如果類已經被加載:
則靜態代碼塊和靜態變量就不用重複執行,再創建類對象時,只執行與實例相關的變量初始化和構造方法。