Oo緣來是你oO


          posts - 120,comments - 125,trackbacks - 0

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


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

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

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

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

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

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


          輸出結果:

          2

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

          此時,在類ClassTest main()中不再有指向ClassX的動態鏈接,告訴ClassTest在運行的時候從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

          }


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

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

          如果用來給static final變量進行初始化的表達式,只能在運行時刻才可以計算出值,那么常量替換就不會發生.例如:

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


          ClassX 改變了,我們再來看一下Main.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

          }


          此時我們可以看見有個引用指向了Field X。
          ( 如果把類ClassX改成Interface,仍然會出現上面的結果 )

          當然有方法可以使你避免出現"inconstant constants"問題。

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

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

          // 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());
          ???}
          }


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

          下一篇準備講一下
          《在java中使用循環定義會出現哪些問題?》


          ?



          馬嘉楠
          jianan.ma@gmail.com

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

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

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

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

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

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

          應該貼一個公告出來啊  回復  更多評論
            
          主站蜘蛛池模板: 东安县| 连云港市| 巴彦淖尔市| 缙云县| 西林县| 蒙城县| 西宁市| 盐山县| 涞水县| 师宗县| 静宁县| 衡山县| 德兴市| 论坛| 古浪县| 桂平市| 石楼县| 双流县| 苍山县| 通州区| 济宁市| 天峻县| 义马市| 巴中市| 太谷县| 胶南市| 平塘县| 新宾| 曲沃县| 句容市| 东海县| 公主岭市| 南阳市| 长寿区| 恩施市| 隆昌县| 西平县| 葫芦岛市| 偏关县| 珲春市| 开阳县|