眾所周知 在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、若對變量賦值的初始化塊在變量定義前時:若變量顯示初始化了則最終為顯示初始化值,否則為初始化塊的賦值。