static 靜態變量和靜態代碼塊的執行順序


 眾所周知 在android中static 修飾的會被稱之為 靜態常量,靜態變量, 靜態方法 ,還有就是靜態代碼塊,用static{ // 代碼塊 非static修飾的方法,變量,常量, 是不能再靜態代碼塊中使用的 } 表示。

       static修飾的 是跟着類走的, 而不是跟隨對象,這個大家都是知道的。 那么大家是否知道它們之間的運行順序的關系呢? 今天, 我就給大家簡單講解一下吧。

 

       靜態常量,靜態變量,靜態方法, 大家都知道是通過類名直接調用的(例如:Demo.getStatic() )。但是靜態代碼塊 大家都沒有主動調用過 對吧。 那它 到底什么時候被執行呢? 讓我來揭曉吧, 其實只要你的代碼在任意地方,動用了靜態代碼塊所屬的類中的 任意東西, 那么該靜態代碼塊 就會馬上執行(說白了就是  靜態代碼塊是這個類最先執行的代碼, 但前提是你要使用這個類, 不使用的話, 這個類中的靜態代碼塊是不會執行的 與靜態變量相比就是看代碼編寫的前后順序,和靜態方法有很大的區別)。 當一個類中 有多個靜態代碼塊的時候,是按照代碼編寫的上下順序先后執行的。

      靜態代碼塊 與 靜態變量之間的關系:

如果你想正確使用兩者的話, 個人建議  你必須把靜態變量定義在靜態代碼塊的前面, 因為兩個的執行是會根據代碼編寫的順序來決定的。這個比較難理解, 我來舉個例子吧, 情況下面代碼:

public class Demo{

          public static int i;

          static{

                i = 20;

                //這里的i, 是可以被用作運算的。

           }

}

這時候如果你在main函數輸出i, 那么i=20;

 

public class Demo{  

          static{

                i = 20;

             //這里的i, 是不能被用作運算的, 因為本質上 i 還未被定義

           }

          public static int i;

}

這時候如果你在main函數輸出i, 那么i=20;

 

 public class Demo{  

          static{

                i = 20;

             //這里的i, 是不能被用作運算的, 因為本質上 i 還未被定義

           }

          public static int i = 1;

}

//但是如果我們給靜態的i附上一個初始值后,那么結果就變了。

這時候如果你在main函數輸出i, 那么i=1;

 

上述的代碼 就其實就是進一步說明 靜態變量 和static修改的靜態代碼塊 運行的順序是根據代碼編寫的先后, 而且第二種寫法毫無意義。 未了避免出現不必要的麻煩, 本人強制建議, 不管是否有在靜態代碼塊中使用 靜態變量, 都應當把靜態變量寫在 靜態代碼塊的上方。 靜態常量的情況 和靜態變量是一樣, 這里就不在做說明了。

 

 

1、執行順序

1.1、一個類中的初始化順序

類內容(靜態變量、靜態初始化塊) => 實例內容(變量、初始化塊、構造器)

1.2、兩個具有繼承關系類的初始化順序

父類的(靜態變量、靜態初始化塊)=> 子類的(靜態變量、靜態初始化塊)=> 父類的(變量、初始化塊、構造器)=> 子類的(變量、初始化塊、構造器)

示例如下:(結果見注釋)

復制代碼
 1 class A {
 2     public A() {
 3         System.out.println("Constructor A.");
 4     }
 5 
 6     {
 7         System.out.println("Instance Block A.");
 8     }
 9     static {
10         System.out.println("Static Block A.");
11     }
12 
13     public static void main(String[] args) {
14         new A();/*
15                  * Static Block A. Instance Block A. Constructor A.
16                  */
17     }
18 }
19 
20 class B extends A {
21     public B() {
22         System.out.println("Constructor B.");
23     }
24 
25     {
26         System.out.println("Instance Block B.");
27     }
28     static {
29         System.out.println("Static Block B.");
30     }
31 
32     public static void main(String[] args) {
33         new A();/*
34                  * Static Block A. Static Block B. Instance Block A. Constructor A.
35                  */
36         System.out.println();
37         new B();/*
38                  * Instance Block A. Constructor A. Instance Block B. Constructor B.
39                  */// 靜態成員和靜態初始化塊只會執行一次。
40     }
41 }
復制代碼

2、對變量值的影響

一個變量,若顯示初始化、初始化塊對該變量賦值、構造方法對該變量賦值同時存在,則變量最終值如何確定?按1節中所述的執行順序確定。

這里考慮初始化塊在變量定義之前的情形,此時會造成迷惑。

 

初始化塊可以對在它之后定義的變量賦值,但不能訪問(如打印)。如:

1     static {
2         a = 3;
3         // int b=a;//Cannot reference a field before it is defined
4         // System.out.println(a);//Cannot reference a field before it is defined
5     }
6     static int a = 1;

“對變量值的影響”是指 對變量賦值的初始化塊位於變量定義之前 時,變量的最終值根據變量定義時是否顯示初始化而會有不同結果(若初始化塊位於變量定義之后,那么變量的值顯然很容易就確定了,不會造成迷惑)。如:

復制代碼
 1 class Test {
 2     static {
 3         a = 3;
 4         // int b=a;//Cannot reference a field before it is defined
 5         // System.out.println(a);//Cannot reference a field before it is defined
 6         b = 3;
 7     }
 8     static int a = 1;
 9     static int b;
10 
11     public static void main(String[] args) {
12         System.out.println(a);//1
13         System.out.println(b);//3
14     }
15 }
復制代碼

判斷方法:

顯示初始化內部隱含 定義變量和對變量進行賦值的初始化塊兩部分,所以初始化塊和顯示初始化哪個在后變量的最終值就是該值。

更多示例:

1:

復制代碼
 1 class C {
 2 
 3     static {
 4         a = 2;
 5         b = 2;
 6     }
 7     static int a;
 8     static int b = 1;
 9 
10     public C() {
11         e = 3;
12     }
13 
14     {
15         c = 2;
16         d = 2;
17         e = 2;
18     }
19     int c;
20     int d = 1;
21     int e = 1;
22 
23     public static void main(String[] args) {
24         System.out.println(C.a);//2
25         System.out.println(C.b);//1
26         System.out.println(new C().c);//2
27         System.out.println(new C().d);//1
28         System.out.println(new C().e);//3
29     }
復制代碼

2:

復制代碼
 1 class C {
 2     public C() {
 3     }
 4 
 5     {
 6         a = 3;
 7     }
 8     static {
 9         a = 2;
10     }
11     static int a;
12     static int b;
13 
14     public static void main(String[] args) {
15         System.out.println(C.a);// 2
16         System.out.println(new C().a);// 3
17         System.out.println(C.b);// 0
18     }
19 }
復制代碼

3:

復制代碼
 1 class C {
 2     // 以下關於靜態初始化的
 3     static {
 4         a = 2;
 5     }
 6     static int a = 1;
 7     static int b = 1;
 8     static {
 9         b = 2;
10         c = 2;
11     }
12     static int c;
13 
14     {
15         d = 2;
16     }
17     int d = 1;
18     int e = 1;
19     {
20         e = 2;
21         f = 2;
22     }
23     int f;
24 
25     public static void main(String[] args) {
26         System.out.println(C.a);// 1
27         System.out.println(C.b);// 2
28         System.out.println(new C().c);// 2
29         System.out.println(new C().d);// 1
30         System.out.println(new C().e);// 2
31         System.out.println(new C().f);// 2
32     }
33 }
復制代碼

 3、總結

執行順序:

1、類內容(靜態變量、靜態初始化塊) => 實例內容(變量、初始化塊、構造器)

2、父類的(靜態變量、靜態初始化塊)=> 子類的(靜態變量、靜態初始化塊)=> 父類的(變量、初始化塊、構造器)=> 子類的(變量、初始化塊、構造器)

 

初始化塊可以對在它之后定義的變量賦值,但不能訪問(如打印)。

變量最終值:一個變量,若顯示初始化、初始化塊對該變量賦值、構造方法對該變量賦值同時存在,則變量最終值如何確定:

1、按執行順序

2、若對變量賦值的初始化塊在變量定義前時:若變量顯示初始化了則最終為顯示初始化值,否則為初始化塊的賦值。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM