我們經常在系統中定義一個常量接口(或常量類),以囊括系統中所涉及的常量,進而簡化代碼,友善開發,在很多的開源項目中已采用了類似的方法,比如在Struts2中,org.apache.struts2.StrutsConstants就是一個常量類,它定義了Struts架構中與配置有關的常量,而org.apache.struts2.StrutsStatics則是一個常量接口,其中定義了OGNL通路的關鍵字。
關于常量接口(類)我們來看一個例子,首先定義一個常量類:


運作的結果非常簡單(結果省略)。目前的代碼編寫都是在“智能型”IDE工具中完成的,下面我們暫時回溯到原始時代,也就是回歸到用記事本編寫代碼的年代,然後看看會發生什麼奇妙事情(為什麼要如此,稍後會給出答案)。
修改常量Constant類,人類的壽命增加了,最大能活到180歲,代碼如下:
然後重新編譯:javac Constant,編譯完成後執行:java Client,(隻執行Client類,不編譯)大家想看看輸出的極限年齡是多少歲嗎?
輸出的結果是:“人類壽命極限是:150”,竟然沒有改變為180,太奇怪了,這是為何?
原因是:對于final修飾的基本類型和String類型,編譯器會認為它是穩定态(Immutable Status),是以在編譯時就直接把值編譯到位元組碼中了,避免了在運作期引用(Run-time Reference),以提高代碼的執行效率。針對我們的例子來說,Client類在編譯時,位元組碼中就寫上了“150”這個常量,而不是一個位址引用,是以無論你後續怎麼修改常量類,隻要不重新編譯Client類,輸出還是照舊。
而對于final修飾的類(即非基本類型),編譯器認為它是不穩定态(Mutable Status),在編譯時建立的則是引用關系(該類型也叫做Soft Final),如果Client類引入的常量是一個類或執行個體,即使不重新編譯也會輸出最新值。
千萬不可小看了這點知識,細坑也能絆倒大象,比如在一個Web項目中,開發人員修改一個final類型的值(基本類型),考慮到重新釋出風險較大,或者是時間較長,或者是審批流程過于繁瑣,反正是為了偷懶,于是直接采用替換class類檔案的方式釋出。替換完畢後應用伺服器自動重新開機,然後簡單測試一下(比如本類引用final類型的常量),一切OK。可運作幾天後發現業務資料對不上,有的類(引用關系的類)使用了舊值,有的類(繼承關系的類)使用的是新值,而且毫無頭緒,讓人一籌莫展,其實問題的根源就在于此。
恩,還有個小問題沒有說明,我們的例子為什麼不在IDE工具(比如Eclipse)中運作呢?那是因為在IDE中不能重制該問題,若修改了Constant類,IDE工具會自動編譯所有的引用類,“智能”化屏蔽了該問題,但潛在的風險其實仍然存在。
注意 釋出應用系統時禁止使用類檔案替換方式,整體WAR包釋出才是萬全之策。
本文轉自SummerChill部落格園部落格,原文連結:http://www.cnblogs.com/DreamDrive/p/5416974.html,如需轉載請自行聯系原作者