????????????????????????????? 在Java中使用循環定義會出現哪些問題
?
??????????????????????????????????????????????
馬嘉楠
??????? 2006-10-19
在上一篇文章《
inconstant constants ( 變化無常的常量 )
? 》的基礎上,我們再來研究一下在 Java 中使用循環定義會出現哪些問題。
老規矩,代碼伺候 ^+^
例1:
public
class
ClassX{
???public?static?final?intX?=?2*
ClassY.Y;
}
public?class
ClassY{
???public?static?final?intY?=ClassZ.Z+?1
;
}
public
class
?ClassZ?
extends
ClassX{
???public?static?final?int?Z=?X?+?3
;
}
public
class?
ClassTest{
???public?static?void
main(String[]?args){
??????System.out.println(ClassX.X
+
ClassY.Y
+
ClassZ.Z);
???}
}
代碼中的static final變量X,Y,Z,循環定義。
你可以先想一下,這個值會是多少?看看與實際結果是否一致。
輸出結果:
15
現在對ClassTest.java進行一點修改,如下:
例2:
public?class
ClassTest{
???public?staticvoid
main(String[]?args){
??????System.out.println(ClassZ.Z
+
ClassY.Y
+
ClassX.X);
???}
}
兩次的輸出結果會一樣么?
我既然這么問了,你肯定會說不一樣,那你知道原因么?你知道這次的輸出結果么?
可以先思考一下。
輸出結果:
8
讓我來告訴你這是怎么回事。
我們可以看見,對于三個staitc final 變量 X,Y,Z,他們的初始化表達式是循環定義的。在編譯期間不能確定它們的值,所以它們是運行期間常量( runtime constants ),編譯器不會進行常量替換。
而且每個表達式的計算將會依賴于類裝載的順序。
例如,為了計算出例1中的 ClassTest 結果,我們可以預見,ClassX 是第一個被裝載的類,但是第一個完成初始化的類卻是 ClassZ.
讓我們一步一步看看都發生了什么。
1.???X = 2 * ClassY.Y;??????計算X,需要知道ClassY.Y的值,下一步計算Y值
2.???Y = ClassZ.Z + 1;??????計算Y,需要知道ClassZ.Z的值,下一步計算Z值
3.???Z = X + 3;??????????????? 計算Z,需要知道X的值,而此時X的值還沒有被計算出來(又轉回來了,居然是個圈,呵呵^+^),所以我們使用X的默認值0。
因此:
??????Z = 3;
??????Y = 4;
??????X = 8;
所以 ClassX.X + ClassY.Y + ClassZ.Z? =? 15
例2當中,也是同一道理
不同的是,ClassZ是第一個被裝載的類,ClassX是第一個完成初始化的類
1. Z = X + 3;
2. X = 2 * ClassY.Y;
3. Y = ClassZ.Z + 1;(此時使用Z的默認值0)
因此:
??????Y = 1;
??????X = 2;
??????Z = 5;
所以 ClassZ.Z + ClassY.Y + ClassX.X = 8
只是簡單的改變的輸出順序,結果卻截然不同。哪一個才是你想要得結果呢?
我的例子看起來有點挖空心思鉆牛角尖,但是在大型項目當中,也許就會出現與例子當中相同的循環定義,如果真的存在的話,那么在紛繁的代碼當中想要發現循環定義可不是件容易的事情。
如果獨立看每一個定義的話,似乎都可以進行常量替換,看不出任何問題。但是這樣的代碼在不久的將來就會引發問題,而且不易被我們所察覺。
在你的應用程序當中不經意的代碼改變(例如示例代碼中我們只是改變了輸出順序,卻產生了截然不同的結果),就會導致不同的類裝載順序和計算順序,或者在并發的線程調度中,可能也會導致致不同的類裝載順序和計算順序。不幸的是,大多數編譯器不認為這種代碼是錯誤,也不會對編程人員給出任何警告。
我只是講了一下循環定義會引發的問題,我暫時也想不出什么好的解決辦法,只能在編程的過程當中盡量注意啦。
注:有錯誤請告訴我,非常感謝!
馬嘉楠
jianan.ma@gmail.com
posted on 2006-10-19 10:58
馬嘉楠 閱讀(2023)
評論(4) 編輯 收藏 所屬分類:
Java