隨筆-57  評論-129  文章-0  trackbacks-0
          最近看見一個JavaEye上關于Java基本類型編譯優化的帖子。
          貌似高深莫測,其實疑點重重。吧內容轉貼過來,希望在這里找到更合理的解釋。
          引用網上看得一些文章

           int a = 3;
           int b = 3;

            編譯器先處理int a = 3;首先它會在棧中創建一個變量為a的引用,然后查找有沒有字面值為3的地址,沒找到,就開辟一個存放3這個字面值的地址,然后將a指向3的地址。接著處 理int b = 3;在創建完b的引用變量后,由于在棧中已經有3這個字面值,便將b直接指向3的地址。這樣,就出現了a與b同時均指向3的情況。

          再令a=4;那么,b不會等于4,還是等于3。在編譯器內部,遇到a=4;時,它就會重新搜索棧中是否有4的字面值,如果沒有,重新開辟地址存放4的值;如果已經有了,則直接將a指向這個地址。因此a值的改變不會影響到b的值

          不知道真正的原理是不是那樣的?

          如果是的話能證明嗎?

          這些描述我也看過,很是不解。

          如果說這種基本類型也需要用這種指針的風格,還要共享數據,那么后續的操作處理起來不是更麻煩嗎?
          每次寫操作都要查找已有常量。甚至開辟新的空間存儲新值。
          再說這個指針怎么的也要個32位吧。為什么就不能直接吧值放進去,硬是要通過指針跳來跳去的,有意義嗎?
          這優化了嗎?

          反正在我看來,這是不可能的。

          希望有高手出來澄清一下,給個合理的解釋。

          如果是對的,那也應該給出有點說服力的證據。
          如果是錯的,那么建議大家吧這篇文章的源頭揪出來,這個確實誤人不淺。

          不過java對 String 這類不可變對象的處理,編譯器確實有類似優化,不過也只是編譯期。
          這種系統類庫受到點編譯器的特別關注倒是很合理的。



          posted on 2007-07-30 08:29 金大為 閱讀(1181) 評論(12)  編輯  收藏 所屬分類: Java

          評論:
          # re: 一片可能是誤認子弟的言論 2007-07-30 09:16 | Unmi
          我怎么沒見過說對
          int a=3;
          int b=b;
          編譯器會作如此的優化呢?從兩次產生的字節碼是不會的

          int a=3;
          int b=3;

          String s1="hello";
          String s2="hello";

          產生的字節碼
          0: iconst_3 //整型常量值3壓棧
          1: istore_1 //從棧中彈出整型值,存到位置為1的局部變量中
          2: iconst_3 //整型常量值3壓棧
          3: istore_2 //從棧中彈出整型值,存到位置為2的局部變量中
          4: ldc #2; //String hello //2號位置的字符串常量壓棧
          6: astore_3 //從棧中彈出字符串值,存到位置為3的局部變量中
          7: ldc #2; //String hello //2號位置的字符串常量壓棧
          9: astore 4 //從棧中彈出字符串值,存到位置為4的局部變量中

          希望從上面的字節碼能讓你理解字符串常量
          我就是不知道你是在哪里看到那篇文章的。  回復  更多評論
            
          # re: 一片可能是誤認子弟的言論 2007-07-30 09:31 | wangzx
          確實是被人誤了。對int這樣的JVM基本類型,根本不存在指針和共享的概念。  回復  更多評論
            
          # re: 一片可能是誤認子弟的言論 2007-07-30 09:38 | 金大為
          我還是在4年前剛開始學Java時看到的,因為對里面的內容實在不敢茍同,感覺就像是那位吃飽了撐著沒事干的大牛吧人家愚人節的blog給翻譯過來了。印象比較深刻。但是,原文在那里,我已經不記得了。總之是一片廣泛流傳的東西。

          這次我是在javaEye的帖子里看到的:http://www.javaeye.com/topic/102430  回復  更多評論
            
          # re: 一篇可能是誤認子弟的言論 2007-07-30 10:18 | Sun
          有些人學了一點東西就自認高手
          什么都敢說
          一點不負責任  回復  更多評論
            
          # re: 一篇可能是誤認子弟的言論 2007-07-30 10:53 | dennis
          我真沒看過這篇文章,不知道在那里有出處,我倒想去看看,這個問題其實看過深入java虛擬機就沒什么疑問了。  回復  更多評論
            
          # re: 一篇可能是誤認子弟的言論 2007-07-30 11:06 | pass86
          學習。  回復  更多評論
            
          # re: 一篇可能是誤認子弟的言論 2007-07-30 11:06 | dennis
          可以肯定是基本類型是沒有什么內存共享和指針的,效率考慮上也不需要。不同的地方在于基本類型變量定義在何處,在類的變量或者方法的局部變量是有一點小差異,類的實例變量和類變量在常量池中有入口,不過他們入口就是他們的值,而不是類似接口、類的符號引用,同樣需要常量池解析這個步驟(直接解析)。而對于靜態的final變量都是在編譯時解析為常量值的本地拷貝。
          public class Test
          {
          int a=3;
          int b=3;
          static int c=3;
          public void test(){
          int a=3;
          int b=3;
          int c=this.c;
          }

          }

          javap -v Test  回復  更多評論
            
          # re: 一篇可能是誤認子弟的言論[未登錄] 2007-07-30 11:31 | dd
          的確是有一個常量池的
          public class dd
          {
          public static void main(String ... args)
          {
          Integer a=-1; //-1到127
          Integer b=-1;
          System.out.println(a==b);
          String str1="dd";
          String str2="dd";
          System.out.println(str1==str2);
          }
          }
          沒有new 出一個對象,值都是存進常量池里的。


            回復  更多評論
            
          # re: 一篇可能是誤認子弟的言論 2007-07-30 11:51 | dennis
          @dd
          你的理解錯了,你的例子中main僅僅是一個方法,里面的變量都是局部變量,這些變量都以指令的形式寫在了字節碼中,當調用方法是,這些變量也僅僅在java棧的局部變量區內,而不是常量池,方法調用也就是入棧出棧的操作。而常量池用于存儲類的名稱、方法和字段名稱以及串常量等信息,這是完全不同的。  回復  更多評論
            
          # re: 一篇可能是誤認子弟的言論 2007-07-30 14:09 | 金大為
          @dd
          我把你這段程序的字節碼貼出來

          // access flags 137
          public static transient varargs main([Ljava/lang/String;)V
          L0 (0)
          LINENUMBER 6 L0
          ICONST_M1
          INVOKESTATIC java/lang/Integer.valueOf(I)Ljava/lang/Integer;
          ASTORE 1
          L1 (4)
          LINENUMBER 7 L1
          ICONST_M1
          INVOKESTATIC java/lang/Integer.valueOf(I)Ljava/lang/Integer;
          ASTORE 2
          L2 (8)
          LINENUMBER 8 L2
          GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
          ALOAD 1
          ALOAD 2
          IF_ACMPNE L3
          ICONST_1
          GOTO L4
          L3 (15)
          ICONST_0
          L4 (17)
          INVOKEVIRTUAL java/io/PrintStream.println(Z)V
          L5 (19)
          LINENUMBER 10 L5
          LDC "dd"
          ASTORE 3
          L6 (22)
          LINENUMBER 11 L6
          LDC "dd"
          ASTORE 4
          L7 (25)
          LINENUMBER 12 L7
          GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
          ALOAD 3
          ALOAD 4
          IF_ACMPNE L8
          ICONST_1
          GOTO L9
          L8 (32)
          ICONST_0
          L9 (34)
          INVOKEVIRTUAL java/io/PrintStream.println(Z)V
          L10 (36)
          LINENUMBER 13 L10
          RETURN
          L11 (38)
          LOCALVARIABLE args [Ljava/lang/String; L0 L11 0
          LOCALVARIABLE a Ljava/lang/Integer; L1 L11 1
          LOCALVARIABLE b Ljava/lang/Integer; L2 L11 2
          LOCALVARIABLE str1 Ljava/lang/String; L6 L11 3
          LOCALVARIABLE str2 Ljava/lang/String; L7 L11 4
          MAXSTACK = 3
          MAXLOCALS = 5  回復  更多評論
            
          # re: 一篇可能是誤認子弟的言論 2007-07-30 14:17 | 金大為
          對于Integer對象的直接原始類型(int)賦值,將編譯成Integer.valueOf(原始int值)。
          兩個Integer對象之所以地址相等,完全是Java5類庫層面的緩存所至。
          與上面討論的常量池無關。
          這個一看Integer.valueOf實現就明白了。  回復  更多評論
            
          # re: 一篇可能是誤認子弟的言論 2007-07-31 14:51 | BruceLuo
          我想起來了,這是臺灣良格GE寫的吧,我沒有記錯的話,他原來的是寫的是int a =100;int b =100吧。。。。希望大家幫忙找下!  回復  更多評論
            
          主站蜘蛛池模板: 荃湾区| 德安县| 湾仔区| 华坪县| 阜新市| 安宁市| 巩义市| 福泉市| 广德县| 罗山县| 乡城县| 贞丰县| 抚远县| 兴安县| 常德市| 开封市| 石台县| 古交市| 清河县| 武平县| 鄢陵县| 长兴县| 台南县| 砚山县| 灌南县| 曲周县| 三亚市| 祁门县| 北川| 铜鼓县| 唐海县| 洛阳市| 离岛区| 溧阳市| 定结县| 台南县| 含山县| 大冶市| 临泽县| 东乡族自治县| 平远县|