建議32: 靜態變量一定要先聲明后賦值
這標題看着讓人很納悶,什么叫做變量一定要先聲明后賦值?Java中的變量不都是先聲明后使用的嗎?難道還能先使用后聲明?能不能暫且不說,我們先來看一個例子,代碼如下:
1 public class Client { 2 public static int i=1; 3 static{ 4 i=100; 5 } 6 public static void main(String[] args) { 7 System.out.println(i); 8 } 9 }
這段程序很簡單,輸出100嘛!對,確實是100,我們再稍稍修改一下,代碼如下:
1 public class Client { 2 static { 3 i = 100; 4 } 5 public static int i = 1; 6 7 public static void main(String[] args) { 8 System.out.println(i); 9 } 10 }
注意,變量i的聲明和賦值調換了位置,現在的問題是:這段程序能否編譯?如果可以編譯那輸出是多少?還要注意:這個變量i可是先使用(也就是賦值)后聲明的。
答案是:可以編譯,沒有任何問題,輸出是1。對,你沒有看錯,輸出確實是1,而不是100。僅僅調換了一下位置,輸出就變了,而且變量i還真是先使用后聲明的,難道這世界真的顛倒了?
這要從靜態變量的誕生說起了,靜態變量是類加載時被分配到數據區(Data Area)的,它在內存中只有一個拷貝,不會被分配多次,其后的所有賦值操作都是值改變,地址則保持不變。我們知道JVM初始化變量是先聲明空間,然后再賦值的,也就是說:
int i=100; 在JVM中是分開執行,等價於: int i; //分配地址空間 i=100; //賦值
靜態變量是在類初始化時首先被加載的,JVM會去查找類中所有的靜態聲明,然后分配空間,注意這時候只是完成了地址空間的分配,還沒有賦值,之后JVM會根據類中靜態賦值(包括靜態類賦值和靜態塊賦值)的先后順序來執行。對於程序來說,就是先聲明了int類型的地址空間,並把地址傳遞給了i,然后按照類中的先后順序執行賦值動作,首先執行靜態塊中i=100,接着執行i=1,那最后的結果就是i=1了。
哦,如此而已,那再問一個問題:如果有多個靜態塊對i繼續賦值呢?i當然還是等於1了,誰的位置最靠后誰有最終的決定權。
有些程序員喜歡把變量定義放到類的底部,如果這是實例變量還好說,沒有任何問題,但如果是靜態變量,而且還在靜態塊中進行了賦值,那這結果可就和你期望的不一樣了,所以遵循Java通用的開發規范“變量先聲明后使用”是一個良好的編碼風格。
注意 再次重申變量要先聲明后使用,這不是一句廢話。