我們都知道,在Java語言中,有靜態字段和實例字段,但是,它們兩者之間的初始化是有區別的。
其中,需要說明的一點就是:靜態字段由類調用,實例字段由對象調用!!!
1. 靜態字段
static 靜態字段 / 靜態變量 的初始化過程,由Java虛擬機JVM加載類後,自動進行靜態字段初始化。
①靜態字段的默認初始化:靜態字段設置爲其類型的默認值。
②靜態字段的聲明初始化:靜態字段設置爲聲明時的初始化值。
③靜態字段的靜態塊初始化:依次調用靜態塊進行初始化。
從源程序的角度看,靜態字段以上三種初始化的順序:
①首先進行默認初始化。
②然後根據聲明初始化、靜態塊初始化這兩者在程序中的順序來依次進行!!!(兩者誰先誰後是不一定的)
2. 實例字段
實例字段 / 實例變量 的初始化過程,由new進行實例初始化。
①實例字段的默認初始化:實例字段設置爲其類型的默認值。
②實例字段的聲明初始化:實例字段設置爲聲明時的初始化值。
③實例字段的實例構造方法初始化:根據實例構造方法簽名,調用實例構造方法進行初始化。
從源程序的角度看,實例字段以上三種初始化的順序:
①首先必須進行默認初始化。
②然後進行聲明初始化。
③最後進行實例構造方法的初始化。
因爲實例字段相對來說,比較好理解,所以我們在這裏重點對靜態字段的初始化進行講解!!!
我們依次來看下面的五個程序!!!👇👇👇
Program Ⅰ: (沒有靜態塊,靜態變量的聲明初始化的順序不同)
class Test1 {
public Test1() {
System.out.println("Test1實例構造函數之前 a="+Test.a+",b="+Test.b);
Test.a++;
Test.b++;
System.out.println("Test1實例構造函數之後 a="+Test.a+",b="+Test.b);
}
}
public class Test {
public static Test1 t=new Test1();
public static int a;
public static int b=10;
public static void main(String[] args) {
System.out.println("最後的結果:a="+Test.a+",b="+Test.b);
}
}
Program Output Ⅰ:
Program Analysis Ⅰ:
按此順序初始化靜態變量:默認初始化→聲明初始化
默認初始化:靜態變量按照聲明的順序依次設置爲該類型的默認值。
聲明初始化:靜態變量按聲明的順序依次設置爲聲明初始化的值,如果沒有聲明初始化就跳過。
靜態字段初始化流程如下:
1. 默認初始化:類被加載後,首先靜態字段會進行默認初始化。結果:t=null,a=0,b=0
2. 聲明初始化:①首先進行靜態字段t的聲明初始化,創建Test1的實例,調用實例構造方法,執行之後的結果:a=1,b=1
②然後進行靜態字段a和b的聲明初始化,因爲靜態字段a沒有聲明初始化,所以就跳過,並執行Test.a++, 此時a=1;但是靜態字段b由聲明初始化,結果b=10。(大家對照這個流程,看一下上面的代碼和運行結果)
Program Ⅱ:(沒有靜態塊,靜態變量的聲明初始化的順序不同)
class Test1 {
public Test1() {
System.out.println("Test1實例構造函數之前 a="+Test.a+",b="+Test.b);
Test.a++;
Test.b++;
System.out.println("Test1實例構造函數之後 a="+Test.a+",b="+Test.b);
}
}
public class Test {
public static int a;
public static int b=10;
public static Test1 t=new Test1();
public static void main(String[] args) {
System.out.println("最後的結果:a="+Test.a+",b="+Test.b);
}
}
Program Output Ⅱ:
Program Analysis Ⅱ:
按此順序初始化靜態變量:默認初始化→聲明初始化
默認初始化:靜態變量按照聲明的順序依次設置爲該類型的默認值。
聲明初始化:靜態變量按聲明的順序依次設置爲聲明初始化的值,如果沒有聲明初始化就跳過。
靜態字段初始化流程如下:
1. 默認初始化:類被加載後,首先靜態字段會進行默認初始化。結果:t=null,a=0,b=0。
2. 聲明初始化:①首先進行靜態字段a和b的聲明初始化,因爲靜態字段a沒有聲明初始化,所以就跳過,結果還是a=0;但 靜態字段b有聲明初始化,所以結果是b=10。
②然後再進行靜態字段t的聲明初始化,創建Test1的實例,調用實例構造方法,Test.a++,Test.b++,執行 之後的結果是a=1,b=11。(大家對照這個流程,看一下上面的代碼和運行結果)
Program Ⅲ:(有靜態塊,靜態塊定義在聲明初始化語句之後)
class Test1 {
public Test1() {
System.out.println("Test1實例構造函數之前 a="+Test.a+",b="+Test.b);
Test.a++;
Test.b++;
System.out.println("Test1實例構造函數之後 a="+Test.a+",b="+Test.b);
}
}
public class Test {
public static Test1 t=new Test1();
public static int a;
public static int b=10;
static {
a=20;
System.out.println("static靜態代碼塊1之後 a="+Test.a+",b="+Test.b);
}
static {
b=30;
System.out.println("static靜態代碼塊2之後 a="+Test.a+",b="+Test.b);
}
public static void main(String[] args) {
System.out.println("最後的結果:a="+Test.a+",b="+Test.b);
}
}
Program Output Ⅲ:
Program Analysis Ⅲ:
按此順序初始化靜態變量:默認初始化→聲明初始化→靜態代碼塊初始化
默認初始化:靜態變量按照聲明的順序依次設置爲該類型的默認值。
聲明初始化:靜態變量按聲明的順序依次設置爲聲明初始化的值,如果沒有聲明初始化就跳過。
靜態代碼塊初始化:按照靜態代碼塊的順序依次設置靜態字段的值。
靜態字段初始化流程如下:
1. 默認初始化:類被加載後,首先靜態字段會進行默認初始化。 結果:t=null,a=0,b=0。
2. 聲明初始化:①首先進行靜態字段t的聲明初始化,創建Test1的實例,調用實力構造方法,執行之後的結果是a=1,b=1
②進行靜態字段a和b的聲明初始化,因爲靜態字段a沒有聲明初始化,所以就跳過,結果還是a=1;但是靜 態字段b有聲明初始化,所以結果是b=10。
3. 靜態代碼塊初始化:①首先執行靜態代碼塊1,對靜態字段a進行靜態塊初始化,結果是a=20,b=10。
②然後執行靜態代碼塊2,對靜態字段b進行靜態塊初始化,結果是a=20,b=30。(大家對照這個流程,看一下上面的代碼和運行結果)
Program Ⅳ:(有靜態塊,靜態塊定義在聲明初始化語句之前)
class Test1 {
public Test1() {
System.out.println("Test1實例構造函數之前 a="+Test.a+",b="+Test.b);
Test.a++;
Test.b++;
System.out.println("Test1實例構造函數之後 a="+Test.a+",b="+Test.b);
}
}
public class Test {
static {
a=20;
System.out.println("static靜態代碼塊1之後 a="+Test.a+",b="+Test.b);
}
static {
b=30;
System.out.println("static靜態代碼塊2之後 a="+Test.a+",b="+Test.b);
}
public static Test1 t=new Test1();
public static int a;
public static int b=10;
public static void main(String[] args) {
System.out.println("最後的結果:a="+Test.a+",b="+Test.b);
}
}
Program Output Ⅳ:
Program Analysis Ⅳ:
按此順序初始化靜態變量:默認初始化→靜態代碼塊初始化→聲明初始化
默認初始化:靜態變量按照聲明的順序依次設置爲該類型的默認值。
靜態代碼塊初始化:按靜態塊的順序依次設置靜態字段的值。
聲明初始化:靜態變量按聲明的順序依次設置爲聲明初始化的值,如果沒有聲明初始化就跳過。
靜態字段初始化流程如下:
1. 默認初始化:類被加載後,首先靜態字段會進行默認初始化。 結果:t=null,a=0,b=0。
2. 靜態代碼塊初始化:①首先執行靜態代碼塊1,對靜態字段a進行靜態塊初始化,結果是a=20,b=0。
②然後執行靜態代碼塊2,對靜態字段b進行靜態塊初始化,結果是a=20,b=30。
3. 聲明初始化:①首先進行靜態字段t的聲明初始化,創建Test1的實例,調用實例構造方法,執行後的結果是a=21,b=31
②然後進行靜態字段a和b的聲明初始化,因爲靜態字段a沒有聲明初始化,所以就跳過,結果還是a=21; 但是靜態字段b有聲明初始化,所以結果是b=10。(大家對照這個流程,看一下上面的代碼和運行結果)
Program Ⅴ:(有靜態塊,聲明初始化語句在兩個靜態塊定義之間)
class Test1 {
public Test1() {
System.out.println("Test1實例構造函數之前 a="+Test.a+",b="+Test.b);
Test.a++;
Test.b++;
System.out.println("Test1實例構造函數之後 a="+Test.a+",b="+Test.b);
}
}
public class Test {
static {
a=20;
System.out.println("static靜態代碼塊1之後 a="+Test.a+",b="+Test.b);
}
public static Test1 t=new Test1();
public static int a;
public static int b=10;
static {
b=30;
System.out.println("static靜態代碼塊2之後 a="+Test.a+",b="+Test.b);
}
public static void main(String[] args) {
System.out.println("最後的結果:a="+Test.a+",b="+Test.b);
}
}
Program Output Ⅴ:
Program Analysis Ⅴ:
按此順序初始化靜態變量:默認初始化→靜態代碼塊1初始化→聲明初始化→靜態代碼塊2初始化
默認初始化:靜態變量按照聲明的順序依次設置爲該類型的默認值。
靜態代碼塊初始化:按靜態塊的順序依次設置靜態字段的值。
聲明初始化:靜態變量按聲明的順序依次設置爲聲明初始化的值,如果沒有聲明初始化就跳過。
靜態字段初始化流程如下:
1. 默認初始化:類被加載後,首先靜態字段會進行默認初始化。 結果:t=null,a=0,b=0。
2. 靜態代碼塊1初始化:對靜態字段a進行靜態塊初始化,結果a=20,b=0。
3. 聲明初始化:①首先進行靜態字段t的聲明初始化,創建Test1的實例,調用實例構造方法,執行之後結果是a=21,b=1。
②然後進行靜態字段a和b的聲明初始化,因爲靜態字段a沒有聲明初始化,所以就跳過,結果還是a=21; 但是靜態字段b有聲明初始化,所以結果是b=10。
4. 靜態代碼塊2初始化:對靜態字段b進行靜態塊初始化,結果a=21,b=30。(大家對照這個流程,看一下上面的代碼和運行結果)
根據上面這五個Java小程序,大家可能覺得比較多,看起來不舒服,但是靜態字段這部分內容還是很重要的!!!
所以希望大家可以耐心的去理解每一個程序代碼,對我們後面的Java知識的學習還是有很大幫助的!!!😊😊😊