Oo緣來是你oO


          posts - 120,comments - 125,trackbacks - 0

          ????????????????????? ????????? inconstant constants ( 變化無常的常量 )??
          ??????????????????????????????????????????
          ??????????????????????????????????????????
          馬嘉楠 ?????????????? 2006-10-18


          看到這個(gè)題目也許你會(huì)感到奇怪,會(huì)想我在胡說八道什么,一定又是起個(gè)怪異的名字,騙取點(diǎn)擊率。還請(qǐng)你耐心看完,如果你有所收獲,那么我很高興;如果你還是覺得上當(dāng)了,那我繼續(xù)努力寫出點(diǎn)有用的東西,呵呵。

          其實(shí)我想了很久,也還是不知道起一個(gè)什么題目好,就套用了《 The Java Language Specification 》中的一個(gè)名詞“ inconstant constants”,我把他翻譯成“變化無常的常量

          注:部分內(nèi)容在《 使用Java中的final變量需要注意的地方 》有提到,不過我轉(zhuǎn)載的原文不夠詳細(xì)深入,這才重新寫一下。

          我們還是來先看一段代碼,由代碼引出問題:

          public class ?ClassX?{
          ???
          public static final int ??X?? = ??? 2
          ?;
          }

          public class
          ClassTest?{
          ???
          public static void
          main(String[]?args){
          ??????System.out.println(ClassX.X);
          ???}
          } ?


          輸出結(jié)果:

          2

          結(jié)果是顯而易見的,這里需要說明的是:
          根據(jù)Java語言規(guī)范,對(duì)于java中的static final變量,如果用一個(gè)在編譯期間(complie time)可以計(jì)算出結(jié)果的表達(dá)式進(jìn)行初始化,則用到此變量的地方會(huì)被該表達(dá)式的結(jié)果所替代。本例中,在編譯期間,ClassTest.main() 函數(shù)中 ClassX.X 將被2所替代。

          此時(shí),在類ClassTest main()中不再有指向ClassX的動(dòng)態(tài)鏈接,告訴ClassTest在運(yùn)行的時(shí)候從ClassX獲得X的值,你可以通過使用javap反編譯器幫助你理解。

          1. 先編譯ClassTest.java文件
          ????????????javac ClassTest.java
          2. 使用javap
          ????????????javap -c ClassTest

          屏幕輸出:

          Complied?from?"ClassTest.java"
          public?class?ClassTest?extends?java.lang.Object{
          public?ClassTest();
          ???Code:
          ??????0:?aload_0
          ??????1:?invokespecial?????#1;?//Method?java/lang/Object."<init>
          ":()V
          ??????4:?return

          public?static?void?main(java.lang.String[]);
          ???Code:
          ??????0:?getstatic?????????#2;?//Field?java/lang/System.out:Ljava/io/PrintStream;
          ??????3:?iconst_2?
          ??????4:?invokevirtua??????#3;?//Method?java/io/PrintStream.println:(I)V
          ??????7:?return

          }


          可以看出,在調(diào)用System.out.println()之前,整數(shù)2已經(jīng)被放在JVM的堆棧中,不再有指向ClassX.X的鏈接。如果此時(shí),改變ClassX.X的值為1,并且重新編譯ClassX.X文件,但是并不重新編譯ClassTest.java文件,運(yùn)行ClassTest,輸出結(jié)果仍然是2.

          這么做(常量替換)的一個(gè)原因是為了在編譯期間檢查switch case語句。switch語句中的每一個(gè)case都需要一個(gè)常量值,而且每?jī)蓚€(gè)之間都不能相同,編譯器在編譯期間將會(huì)做檢查。

          如果用來給static final變量進(jìn)行初始化的表達(dá)式,只能在運(yùn)行時(shí)刻才可以計(jì)算出值,那么常量替換就不會(huì)發(fā)生.例如:

          public class ClassX?{
          ???public static?final?int?X?=?new?
          java.util.Random().nextInt();
          } ?


          ClassX 改變了,我們?cè)賮砜匆幌翸ain.main():

          Complied?from?"ClassTest.java"
          public?class?ClassTest?extends?java.lang.Object{
          public?ClassTest();
          ???Code:
          ??????0:?aload_0
          ??????1:?invokespecial??????#1;?//Method?java/lang/Object."<init>
          ":()V
          ??????4:?return

          public?static?void?main(java.lang.String[]);
          ???Code:
          ??????0:?getstatic????????? #2;?//Field?java/lang/System.out:Ljava/io/PrintStream;
          ??????3:?getstatic????????? #3;?//Field?ClassX.X:I?
          ??????6:?invokevirtual??????#4;?//Method?java/io/PrintStream.println:(I)V
          ??????9:?return

          }


          此時(shí)我們可以看見有個(gè)引用指向了Field X。
          ( 如果把類ClassX改成Interface,仍然會(huì)出現(xiàn)上面的結(jié)果 )

          當(dāng)然有方法可以使你避免出現(xiàn)"inconstant constants"問題。

          第一種方法:
          當(dāng)你要聲明一個(gè)編譯期間常量的時(shí)候,一定要保證此變量不會(huì)或者不太可能改變,或者盡量少使用聲明為static final的變量。當(dāng)然這只能治標(biāo)不能治本,所以我推薦使用第二種方法。

          第二種方法:
          將變量聲明為private,同時(shí)聲明一個(gè)方法來獲得此變量的值

          // ClassX.java修改如下:?
          public class? ClassX?{
          ???private?static?final?int?X?=?2
          ;
          ???public? static int
          getX(){
          ??????return
          X;
          ???}
          }

          // ClassTest.java修改如下:?

          public?class? ClassTest{
          ???public?static?void?
          main(String[]?args){
          ??????System.out.println(ClassX.getX());
          ???}
          }


          此時(shí)再改變ClassX.X的值為1,重新編譯ClassX.java,而不編譯ClassTest,結(jié)果就會(huì)顯示1,而非2。這就避免了"inconstant constants"的問題。

          下一篇準(zhǔn)備講一下
          《在java中使用循環(huán)定義會(huì)出現(xiàn)哪些問題?》


          ?



          馬嘉楠
          jianan.ma@gmail.com

          posted on 2006-10-18 16:27 馬嘉楠 閱讀(1618) 評(píng)論(5)  編輯  收藏 所屬分類: Java

          FeedBack:
          # re: inconstant constants(變化無常的常量)
          2006-10-18 21:24 | Flyingis
          下次記得可以將字體大小和格式稍調(diào)整一下,看起來舒服一點(diǎn)。

          寫的不錯(cuò)啊。  回復(fù)  更多評(píng)論
            
          # re: inconstant constants(變化無常的常量)
          2006-10-18 22:08 | 馬嘉楠
          @Flyingis
          謝謝^+^

          我把字體改為3號(hào)了,確實(shí)看起來舒服很多
          問一下你得代碼和文字都用什么字體啊?
          我總是調(diào)不好  回復(fù)  更多評(píng)論
            
          # re: inconstant constants(變化無常的常量)
          2006-10-19 10:26 | Flyingis
          1.Word/OneNote直接粘貼過來的文章多余代碼比較多,格式會(huì)有問題,建議在粘貼過來后清除一下Word代碼。
          2.正文字號(hào)我一般用2號(hào)。
          3.漢字字體為宋體,英文字母為Verdana,全選然后選擇字體為Verdana即可,漢字默認(rèn)就是宋體。  回復(fù)  更多評(píng)論
            
          # re: inconstant constants(變化無常的常量)
          2006-10-19 10:40 | 馬嘉楠
          我都是先在記事本上面寫的,寫得差不多了,粘貼過來,再做些修改就發(fā)布。

          今天凌晨開始就有問題了,開始不能登陸,之后就一直不能編輯,也許新版本升級(jí)?維護(hù)不用這么長(zhǎng)時(shí)間吧。

          等可以編輯了,再來修改一下  回復(fù)  更多評(píng)論
            
          # re: inconstant constants(變化無常的常量)
          2006-10-19 11:21 | 馬嘉楠
          60天內(nèi)閱讀排行
          增加了這個(gè)功能
          還是不能編輯,不知道還有什么東西改動(dòng)

          應(yīng)該貼一個(gè)公告出來啊  回復(fù)  更多評(píng)論
            
          主站蜘蛛池模板: 罗源县| 文化| 临朐县| 聊城市| 凤庆县| 清水河县| 白朗县| 探索| 三河市| 平谷区| 新津县| 耒阳市| 内丘县| 工布江达县| 文昌市| 广丰县| 牙克石市| 邻水| 金坛市| 凯里市| 大石桥市| 年辖:市辖区| 徐汇区| 剑川县| 汾阳市| 新干县| 河池市| 寻甸| 迁西县| 北票市| 启东市| 金华市| 湖南省| 株洲县| 蓬安县| 攀枝花市| 大渡口区| 翁源县| 丽水市| 嵊州市| 静海县|