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