您的位置:本站首頁-JAVA指導-JAVA字符謎題8:字符串奶酪
下面的程序從一個字節序列創建了一個字符串,然后迭代遍歷字符串中的字符,并將它們作為數字打印。請描述一下程序打印出來的數字序列:public class StringCheese { public static void main(String[] args) { byte bytes[] = new byte[256]; for (int i = 0; i < 256; i++) bytes[i] = (byte)i; String str = new String(bytes); for (int i = 0, n = str.length(); i < n; i++) System.out.println((int)str.charAt(i) + " "); } }首先,byte數組用從0到255每一個可能的byte數值進行了初始化,然后這些byte數值通過String構造器被轉換成了char數值。最后,char數值被轉型為int數值并被打印。打印出來的數值肯定是非負整數,因為char數值是無符號的,因此,你可能期望該程序將按順序打印出0到255的整數。
如果你運行該程序,可能會看到這樣的序列。但是在運行一次,可能看到的就不是這個序列了。我們在四臺機器上運行它,會看到四個不同的序列,包括前面描述的那個序列。這個程序甚至都不能保證會正常終止,比打印其他任何特定字符串都要缺乏這種保證。它的行為完全是不確定的。
這里的罪魁禍首就是String(byte[])構造器。有關它的規范描述道:“在通過解碼使用平臺缺省字符集的指定byte數組來構造一個新的String時,該新String的長度是字符集的一個函數,因此,它可能不等于byte數組的長度。當給定的所有字節在缺省字符集中并非全部有效時,這個構造器的行為是不確定的”[ Java -API]。
到底什么是字符集?從技術角度上講,它是“被編碼的字符集合和字符編碼模式的結合物”[Java-API]。換句話說,字符集是一個包,包含了字符、表示字符的數字編碼以及在字符編碼序列和字節序列之間來回轉換的方式。轉換模式在字符集之間存在著很大的區別:某些是在字符和字節之間做一對一的映射,但是大多數都不是這樣。ISO-8859-1是唯一能夠讓該程序按順序打印從0到255的整數的缺省字符集,它更為大家所熟知的名字是Latin-1[ISO-8859-1]。
J2SE運行期環境(JRE)的缺省字符集依賴于底層的操作系統和語言。如果你想知道你的JRE的缺省字符集,并且你使用的是5.0或更新的版本,那么你可以通過調用java.nio.charset.Charset.defaultCharset()來了解。如果你使用的是較早的版本,那么你可以通過閱讀系統屬性“file.encoding”來了解。
幸運的是,你沒有被強制要求必須去容忍各種稀奇古怪的缺省字符集。當你在char序列和byte序列之間做轉換時,你可以且通常是應該顯式地指定字符集。除了接受byte數字之外,還可以接受一個字符集名稱的String構造器就是專為此目的而設計的。如果你用下面的構造器去替換在最初的程序中的String構造器,那么不管缺省的字符集是什么,該程序都保證能夠按照順序打印從0到255的整數:
String str = new String(bytes, "ISO-8859-1");這個構造器聲明會拋出UnsupportedEncodingException異常,因此你必須捕獲它,或者更適宜的方式是聲明main方法將拋出它,要不然程序不能通過編譯。盡管如此,該程序實際上不會拋出異常。Charset的規范要求Java平臺的每一種實現都要支持某些種類的字符集,ISO-8859-1就位列其中。
這個謎題的教訓是:每當你要將一個byte序列轉換成一個String時,你都在使用某一個字符集,不管你是否顯式地指定了它。如果你想讓你的程序的行為是可預知的,那么就請你在每次使用字符集時都明確地指定。對API的設計者來說,提供這么一個依賴于缺省字符集的String(byte[])構造器可能并非是一個好主意。
posted on 2007-04-24 12:03 sooxin 閱讀(201) 評論(0) 編輯 收藏 所屬分類: JAVA