隨筆 - 1  文章 - 3  trackbacks - 0
          <2025年6月>
          25262728293031
          1234567
          891011121314
          15161718192021
          22232425262728
          293012345


          常用鏈接

          留言簿(1)

          隨筆檔案

          文章分類

          文章檔案

          相冊

          搜索

          •  

          最新評論

          • 1.?re: EXT亂碼
          • @lyq
            我們用的是UTF-8
          • --gkc
          • 2.?re: EXT亂碼
          • 你們工程里面用的編碼格式是utf-8嗎?如果不是的話,怎么只要把method=“post”就行了呢?

            那如果編碼格式是 gbk/gb2312,中文亂碼的問題怎么處理的呢?
          • --lyq
          • 3.?re: EXT出錯:undefined
          • 謝了,哥們.我也折騰了N久,最后被你的帖啟發了!
          • --小波
          String類在java中被大量運用,甚至在class文件中都有其身影,因此將其設計為簡單輕便的非可變類是比較合適的。

           

          一、創建。
          好了,知道String是非可變類以后,我們可以進一步了解String的構造方式了。創建一個Stirng對象,主要就有以下兩種方式:
          java 代碼

          1. String str1 = new String("abc");
          2. Stirng str2 = "abc";

           

          雖然兩個語句都是返回一個String對象的引用,但是jvm對兩者的處理方式是不一樣的。對于第一種,jvm會馬上在heap中創建一個String對象,然后將該對象的引用返回給用戶。對于第二種,jvm首先會在內部維護的strings pool中通過String的 equels 方法查找是對象池中是否存放有該String對象,如果有,則返回已有的String對象給用戶,而不會在heap中重新創建一個新的String對象;如果對象池中沒有該String對象,jvm則在heap中創建新的String對象,將其引用返回給用戶,同時將該引用添加至strings pool中。注意:使用第一種方法創建對象時,jvm是不會主動把該對象放到strings pool里面的,除非程序調用 String的intern方法。看下面的例子:
          java 代碼

          1. String str1 = new String("abc"); //jvm 在堆上創建一個String對象
          2.
          3. //jvm 在strings pool中找不到值為“abc”的字符串,因此
          4. //在堆上創建一個String對象,并將該對象的引用加入至strings pool中
          5. //此時堆上有兩個String對象
          6. Stirng str2 = "abc";
          7.
          8. if(str1 == str2){
          9. System.out.println("str1 == str2");
          10. }else{
          11. System.out.println("str1 != str2");
          12. }
          13. //打印結果是 str1 != str2,因為它們是堆上兩個不同的對象
          14.
          15. String str3 = "abc";
          16. //此時,jvm發現strings pool中已有“abc”對象了,因為“abc”equels “abc”
          17. //因此直接返回str2指向的對象給str3,也就是說str2和str3是指向同一個對象的引用
          18. if(str2 == str3){
          19. System.out.println("str2 == str3");
          20. }else{
          21. System.out.println("str2 != str3");
          22. }
          23. //打印結果為 str2 == str3

          再看下面的例子:
          java 代碼

          1. String str1 = new String("abc"); //jvm 在堆上創建一個String對象
          2.
          3. str1 = str1.intern();
          4. //程序顯式將str1放到strings pool中,intern運行過程是這樣的:首先查看strings pool
          5. //有沒“abc”對象的引用,沒有,則在堆中新建一個對象,然后將新對象的引用加入至
          6. //strings pool中。執行完該語句后,str1原來指向的String對象已經成為垃圾對象了,隨時會
          7. //被GC收集。
          8.
          9. //此時,jvm發現strings pool中已有“abc”對象了,因為“abc”equels “abc”
          10. //因此直接返回str1指向的對象給str2,也就是說str2和str1引用著同一個對象,
          11. //此時,堆上的有效對象只有一個。
          12. Stirng str2 = "abc";
          13.
          14. if(str1 == str2){
          15. System.out.println("str1 == str2");
          16. }else{
          17. System.out.println("str1 != str2");
          18. }
          19. //打印結果是 str1 == str2
          20.

          為什么jvm可以這樣處理String對象呢?就是因為String的非可變性。既然所引用的對象一旦創建就永不更改,那么多個引用共用一個對象時互不影響。


          二、串接(Concatenation)。
          java程序員應該都知道濫用String的串接操作符是會影響程序的性能的。性能問題從何而來呢?歸根結底就是String類的非可變性。既然 String對象都是非可變的,也就是對象一旦創建了就不能夠改變其內在狀態了,但是串接操作明顯是要增長字符串的,也就是要改變String的內部狀態,兩者出現了矛盾。怎么辦呢?要維護String的非可變性,只好在串接完成后新建一個String 對象來表示新產生的字符串了。也就是說,每一次執行串接操作都會導致新對象的產生,如果串接操作執行很頻繁,就會導致大量對象的創建,性能問題也就隨之而來了。
          為了解決這個問題,jdk為String類提供了一個可變的配套類,StringBuffer。使用StringBuffer對象,由于該類是可變的,串接時僅僅時改變了內部數據結構,而不會創建新的對象,因此性能上有很大的提高。針對單線程,jdk 5.0還提供了StringBuilder類,在單線程環境下,由于不用考慮同步問題,使用該類使性能得到進一步的提高。

          三、String的長度
          我們可以使用串接操作符得到一個長度更長的字符串,那么,String對象最多能容納多少字符呢?查看String的源代碼我們可以得知類String中是使用域 count 來記錄對象字符的數量,而count 的類型為 int,因此,我們可以推測最長的長度為 2^32,也就是4G。
          不過,我們在編寫源代碼的時候,如果使用 Sting str = "aaaa";的形式定義一個字符串,那么雙引號里面的ASCII字符最多只能有 65534 個。為什么呢?因為在class文件的規范中, CONSTANT_Utf8_info表中使用一個16位的無符號整數來記錄字符串的長度的,最多能表示 65536個字節,而java class 文件是使用一種變體UTF-8格式來存放字符的,null值使用兩個字節來表示,因此只剩下 65536- 2 = 65534個字節。也正是變體UTF-8的原因,如果字符串中含有中文等非ASCII字符,那么雙引號中字符的數量會更少(一個中文字符占用三個字節)。如果超出這個數量,在編譯的時候編譯器會報錯。

          對String類的理解網上有很多的資料,個人覺得很多都是錯誤的,錯誤的解釋危害性更大。所以為了解釋清楚,就來看代碼,代碼運行出的結果才是最具有說服力的。說明:以下都是個人的理解,歡迎指正。
          Java代碼 復制代碼

          1. public class StringTest {
          2. public static void main(String[] args) {
          3. String str1 = new String("abc");
          4.
          5. String str2 = "abc";
          6.
          7. if (str1 == str2) {
          8. System.out.println("str1 == str2");
          9. } else {
          10. System.out.println("str1 != str2");
          11. }
          12.
          13. String str3 = "abc";
          14. if (str2 == str3) {
          15. System.out.println("str2 == str3");
          16. } else {
          17. System.out.println("str2 != str3");
          18. }
          19.
          20. str1 = str1.intern();
          21.
          22. if (str1 == str2) {
          23. System.out.println("str1 == str2");
          24. } else {
          25. System.out.println("str1 != str2");
          26. }
          27.
          28. String str4 = new String("abc");
          29. str4 = str4.intern();
          30.
          31. if (str1 == str4) {
          32. System.out.println("str1 == str4");
          33. } else {
          34. System.out.println("str1 != str4");
          35. }
          36. }
          37.
          38. }


          運行結果:

          str1 != str2
          str2 == str3
          str1 == str2
          str1 == str4


          看看運行結果后,給出我自己的理解說明:

          1、String有一個所謂的String pool,這是一個什么東西呢,我理解是它是堆(heap)上特殊的一個空間(我叫它特殊堆)。注意它也是在堆上。

          2、產生String類型的對象有兩種方法,那么這兩種方法有什么區別呢?我的理解是String str = “abc”是先用equals方法(String類覆蓋了equals方法)判斷這個特殊堆(String pool)是否有abc,有則將原來在棧中指向abc的引用賦值給str,否則就在這個特殊堆(String pool)上創建一個abc對象。String str2 = new String("abc")則是在普通堆上創建abc對象。所以str和str2是指向不同的對象,它們是不同的。

          3、String有個intern()方法,這個方法是個本地方法,當用String str2 = new String("abc")來創建對象時,它相當于告訴JVM,我這個abc對象是放在特殊堆(String pool)上的。所以第三個打印結果是相等的。

          4、需要注意的一點:String是final類,它是恒定類,一旦創建就無法改變,所以用intern()方法是重新在String pool中創建了一個新的對象。

          5、String類有一個伴隨類StringBuffer,需要了解它們之間的區別請google之。

          posted on 2009-10-13 11:56 ...... 閱讀(110) 評論(0)  編輯  收藏 所屬分類: JAVA

          只有注冊用戶登錄后才能發表評論。


          網站導航:
           
          主站蜘蛛池模板: 从化市| 民丰县| 兴和县| 广河县| 旅游| 华亭县| 鹿邑县| 赣榆县| 宜宾县| 呼玛县| 稻城县| 紫云| 长垣县| 称多县| 隆化县| 武城县| 遂宁市| 伽师县| 江城| 吉隆县| 隆德县| 彰化县| 盐池县| 许昌市| 宜昌市| 马鞍山市| 应城市| 南康市| 中西区| 德庆县| 瑞昌市| 南郑县| 金乡县| 繁峙县| 丹棱县| 平塘县| 延庆县| 平和县| 揭东县| 会东县| 黎川县|