posts - 30,  comments - 28,  trackbacks - 0

          自己想的一道題,算是30%原創吧?
          String a=new String("Hello");
          ? a+="World";

          ?問:a的內容最后是什么?
          ???????? 這兩個語句,共生成了幾個Java對象?

          簡單不?看樣子非常簡單吧,呵呵。
          第一問:a(確切地說a引用的內容)是HelloWorld
          ?
          第二問: 兩個語句,一共生成了幾個對象?
          ????看第一個語句,說實話,用這種方式初始化String,實在是代碼垃圾。這先不管啦。這個語句是老生長談,一個或兩個對象。
          ??? 為何?第一次執行時創建了二個, 一個為字面量"Hello"(它本身是一個String對象), 一個為new String("Hello")(它是通過new創建的, 功能上和字面量"foo"完全一樣, 但卻是另一個對象).

          第二次執行時, 只創建一個, 即new String("Hello"), 這是因為: "Hello"作為String字面量, 是存在于String Pool里面的, 第二次使用它時, 直接指向原有的String, 而不再創建新的String; 但new String("Hello")卻每執行一次都創建一個新的,完全一樣的String對象.

          ???第二個語句呢?
          ???? 3個對象。
          ???? 首先是“World”,毋庸質疑。
          ???? 那么然后呢?注意了,String是final類,不可改變。平時我們寫Java會有個錯覺,stringA+stringB就以為是前者尾巴接上后者腦袋。的確,在C/C++里就是如此。一點兒錯都沒有。
          ??? 但是Java不是,Java設計者為了更多方面的考慮,他們把String設計成了final。
          ??? 看一下JVM匯編指令吧
          ? 0:?aload_0
          ?? 1:?invokespecial?#1; //Method java/lang/Object."<init>":()V
          ?? 4:?return

          static void inti();
          ? Code:
          ?? 0:?new?#2; //class java/lang/String
          ?? 3:?dup
          ?? 4:?ldc?#3; //String Hello
          ?? 6:?invokespecial?#4; //Method java/lang/String."<init>":(Ljava/lang/String;)V
          ?? 9:?astore_0
          ?? 10:?new?#5; //class java/lang/StringBuilder
          ?? 13:?dup
          ?? 14:?invokespecial?#6; //Method java/lang/StringBuilder."<init>":()V
          ?? 17:?aload_0
          ?? 18:?invokevirtual?#7; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
          ?? 21:?ldc?#3; //String Hello
          ?? 23:?invokevirtual?#7; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
          ?? 26:?invokevirtual?#8; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
          ?? 29:?astore_0
          ?? 30:?return

          }

          仔細看一下我做的標記,JVM給我們生成了一個StringBuilder類。(我用的是JDK5,舊版本是StringBuffer類,單單這一點小改動就能讓Java的速度提高很多)。讓后用append方法載入Hello和World兩個String的引用(明確地說轉化成字符數組)。
          當載入完成后,StringBuilder實例調用toString,生成一個新的String實例(暫時稱為TempString)。
          ?最后把引用a指向TempString


          總結:兩句語句總共生成了4個或5個Java類實例

          PS:Java中沒有指針實在是太不方便了。特別是在操作原始數據類型的時候。個人認為Java應該在這點上學學C#。指針不是洪水猛獸,對優秀程序員而言,指針是編程中的一種享受。
          ??????? 希望“海豚”(Java7)能出現指針吧---很不現實,還是等開源后的Java版本吧


          posted on 2006-08-14 03:18 murainwood 閱讀(510) 評論(4)  編輯  收藏 所屬分類: Java讀書筆記


          FeedBack:
          # re: 繼續鞏固Java基礎,一道綜合題
          2006-09-19 21:19 | Winnie
          String a=new String("Hello");
          a+="World";
          總結:兩句語句總共生成了4個或5個Java類實例

          你好,看了你的結論我有些不明白,是否可以指教一二?
          最近正巧在看關于Java字面量方面的內容,看過來的總結就是Java的字面量可以理解為Java的常量,而String類型的字面量呢,是保存于字符串緩沖池中的,所以我覺得就上面的代碼而言,如果我們只討論它執行一次生成幾個String類實例,你在文中提到“第一次執行時創建了二個, 一個為字面量"Hello"(它本身是一個String對象), 一個為new String("Hello")”我的理解是:第一個語句生成了一個String類的實例,而且同時有一個引用變量a指向該String實例,而第二個語句才在字面量緩沖池中生成了一個helloworld和world的實例,此時引用變量a指向helloworld字面量,總結下來應該是又生成兩個實例,那么一共應該是生成三個String實例。
          如果說要執行多次的話,那么每一次都要增加一個String實例,因為有第一個語句。
          我的理解不曉得正確與否,因為我只是看了一些介紹,并不懂得看JVM的匯編語句  回復  更多評論
            
          # re: 繼續鞏固Java基礎,一道綜合題
          2006-09-20 17:36 | murainwood
          "Hello"如果是第一次出現,會生成一個新的實例,然后放入常量Pool中。
          調用了new 語句,總能新生成一個對象實例。
          所以 String a="Hello"和 String a=new String("Hello")是不同的。而且后者被認為是"劣質代碼"
          而a+="World";這個你可以用javap -c 來看JVM匯編碼。
          String做所謂的"連接"時,總是通過臨時變量 StringBuffer 或StringBuilder來實現的。(后者是JDK5.0中的新類,是一個多線程不安全的StringBuffer)
            回復  更多評論
            
          # re: 繼續鞏固Java基礎,一道綜合題
          2006-09-20 19:17 | Winnie
          正巧我對在網上看到的一些內容不是很了解,在此可否再請教一下:
          “String a="Hello"和 String a=new String("Hello")是不同的”
          據我在網上看到的一些資料可以這么解釋:前者是生成一個引導變量a,然后查看“字符串池”中是否有hello這個常量,如果有,直接把該常量的內存地址賦值給a,如果沒有,則在“字符串池”中創建一個hello實例,將新創建的內存自己賦值給a;而后者是生成一個引導變量a,同時創建一個字符串實例,將該字符串實例的內存地址賦值給a。
          你在上文中提到“"Hello"如果是第一次出現,會生成一個新的實例,然后放入常量Pool中。”。我看到的一些資料說,字符串池可以理解為一塊特殊的地方,和內存稍有區別。如果hello是第一次出現,那么給該實例開辟的內存空間可否認為是在pool中的,以后再次出現new語句時,再另外開辟內存空間?
          換言之,String a=new String("Hello")第一次運行中,開辟了一個內存空間,且把該空間算到pool中去,如果pool中沒有hello實例的話?  回復  更多評論
            
          # re: 繼續鞏固Java基礎,一道綜合題
          2006-09-20 21:08 | murainwood
          我的觀點是可以反過來想。
          下面是我寫的代碼
          //:~To compare the reference of string
          public class StringConstPool {

          /**
          * @param args
          */
          public static void main(String[] args) {

          String the1st="hello";

          String the2ed="hello";

          //the result is "the two string are Same"
          //so i'm sure the the1st and the2ed refer the same address
          System.out.println("The two strings are "+(the1st==the2ed?"Same":"Different"));

          String the3ed=new String("hello");
          //the result is different from upper
          //so the the3ed refers another address,thought they have
          System.out.println("The two strings are "+(the1st==the3ed?"Same":"Different"));

          }

          }

          可以看到,變量the1st 和 the2ed 所指的地址是一樣的。而the3ed則是另外的地址。
          我認為的常量池的觀點是正確的,String the2ed="hello"這語句甚至一個對象實例都沒有創造!

          這是JDK API中文版的說明:
          String
          public String(String original)初始化一個新創建的 String 對象,表示一個與該參數相同的字符序列;換句話說,新創建的字符串是該參數字符串的一個副本。由于 String 是不可變的,不必使用該構造方法,除非需要 original 的 顯式副本。

          很明白了吧?  回復  更多評論
            
          <2006年8月>
          303112345
          6789101112
          13141516171819
          20212223242526
          272829303112
          3456789

          如果真的給你一片天,你敢不敢要?

          常用鏈接

          留言簿(3)

          隨筆分類

          隨筆檔案

          相冊

          搜索

          •  

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 鹤庆县| 繁昌县| 余江县| 延津县| 敦化市| 邵阳县| 阳城县| 阜南县| 黄山市| 大埔县| 原阳县| 景德镇市| 邻水| 秭归县| 息烽县| 瑞昌市| 肃南| 海南省| 东港市| 峨眉山市| 金华市| 宕昌县| 洱源县| 合作市| 辽中县| 安义县| 德保县| 汽车| 吉安市| 那曲县| 绥德县| 高平市| 正蓝旗| 新密市| 和平县| 烟台市| 稷山县| 耿马| 腾冲县| 宜昌市| 厦门市|