1. 程式人生 > >轉:Java中String與byte[]的轉換

轉:Java中String與byte[]的轉換

輸出字符串 單個字符 linu 編輯 繁體 中國人 對象 本質 計算機基礎知識

String s = "fs123fdsa";//String變量 

byte b[] = s.getBytes();//String轉換為byte[]

String t = new String(b);//bytep[]轉換為String

做JAVA經常會碰到中文亂碼問題,還有各種編碼的問題,特別是String類的內容需要重新編碼的問題。要解決這些問題,必須了解清楚JAVA對於字符串是怎麽處理的。

1. “字符”是由數字來表示的

先來重新了解一下計算機是如何處理“字符”的,這個原理是大家必須記住的,特別是在用JAVA寫程序的時候,萬萬不可模糊。我們知道,計算機把任何東西都用數字來表示,“字符”也不例外。比如我們要顯示一個阿拉伯數字“3”,在我們的PC裏,其實並不是僅僅用一個數字3來代表我們要寫的“3”,而是以十六進制的0x33來代表,包括放在內存或者是寫到文件裏,其實都是寫著0x33的,不信你可以編輯一個文本文件,寫一個“3”,然後用ultraEdit看他的原始碼。

2. 一切“字符”都必定用數字+編碼表表示。
這時候,有一個問題:為什麽一定要用0x33來代表“3”呢?而不用0x43來代表呢?或者是直接用0x03來代替?其實用什麽來代表都可以,只不過大家都習慣了用ASCII編碼表(是美國國家信息交換表)來確定各字符應該是用什麽數字代表的。同樣,為了表示中國字,我國也指定了中文的編碼表,其中最廣泛使用的是GB2312。比如中文的“當”字,就是用0xB5, 0xB1這兩個八位的數字來表示的。所以如果顯示字符的程序不知道一列數字到底是按什麽編碼表編碼的,他也無法去判斷到底這些是什麽文字。如果隨便用一個不對的編碼表來處理這些數字,處理出來的字符很可能完全是錯的。比如在英文系統上,沒有GB2312編碼表,送給他一個0xB5,0xB1,他就傻傻的當作ASCII來處理(操作系統通常都有自己默認的編碼表),結果顯示出來就是兩個奇怪的符號,因為這兩個字在ASCII表裏就是那兩個符號。同樣在繁體中文系統裏,他的編碼表是BIG5,顯示出來也是一個奇怪的中文,不是“當”字。

3. UNICODE讓全世界都說一種語言
看完上面的文字,是否覺得,世界有那麽多語言,每個都有自己的一套編碼表,很麻煩呢?就算是中文,也有兩套流行的編碼表,一個是GB2312,一個是BIG5。要使用不同中文的編碼的字符時,還要轉來轉去,的確很麻煩。不光這個,如果想要寫一篇包含很多過國文字的文章,就麻煩了,必須要讓處理這個文章的程序知道,哪個字是什麽編碼標準的。如果你想要在文章裏找一個字,也必須指定你要找的是哪種編碼的哪個字。否則,你要找一個0xB5,0xB1的中文“當”字,很可能把同樣數字表示的日文、波蘭文這些不相幹的字一起給你找出來,夠麻煩的吧!
所以人們想,不如大家都用同一個編碼標準吧,各種文字都在編碼表裏有一席之地,處理文字的程序只需要都按這個編碼表來處理就可以了。不過要一個編碼表裏包含所有的文字,這張表就大了,本來英文字+數字一共只有128個以內。但加上中文後,忽然就多了數萬個,所以存放一個字符需要的大小也大了很多。現在UNICODE規定了一個字符必須由2個8位數字來表示,想想,8x8x8x8x = 65536 ,是多大的一個數字啊!所以全世界的文字才能都包含進去。當然拉,也有人說中國字可能都不止6萬個拉,還要包括別的文字,但人家外國人覺得你們中國人常用的也沒那麽多,所以就這麽定了,我們也沒辦法。需要註意的是GB2312和UNICODE雖然都是用兩個8位數來代表一個中文字,但具體的規格可不一樣,比如0xB5,0xB1在UNICODE裏面可不是“當”字,而是另外一國的文字來的。

4. C是如何簡潔的處理字符的

我們來談談C的字符串。C語言誕生在JAVA之前,C語言的基本數據類型是沒有字符串這個類型的,它只有char[]。也就是C把字符順序放入一個字節數組就完了。而且C也不管放在數組裏的是什麽文字,也不管那些字是按什麽編碼標準的。而且他的char的大小也不一定是8位數字,有時候是16位也可能,這要看具體的機器和操作系統。所以寫程序的人必須要知道正在處理的char[]的內容到底是按什麽編碼表表示的字符串,要知道如果比較兩國文字是否相同,可是沒任何意義的哦!

5. JAVA是是如何處理字符的。
世界總會進步的,JAVA就是一個例子。JAVA終於有了String類了,它是解決字符問題的最好工具。在JAVA裏,一個基本的要點是:String類對象是不需要指定編碼表的!為什麽它會自己知道一堆數字各代表什麽字符呢?就是因為String裏的字符信息是用UNICODE編碼存放的。而JAVA為了表示字符(註意是單個字符),也有char這個數據類型,而且他的大小是固定2個8位16進制數字長度,也就是0~65535羅。為的就是對應UNICODE裏面的一個字符。大家如果想取一個String裏的按UNICODE數字,可以用getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin) 方法取得一個char[],這個char[]裏就是表示String字符的,按UNICODE編碼表編碼的數字。
可惜現在絕大多數的系統和程序都不是按UNICODE來處理字符,而JAVA程序總是要和別的程序和系統交換數據的,所以在接收一個字符,或者是發送一個字符的時候,就必須要留意當前系統和UNICODE的關系了。比如你從網絡或者文件接受到一數字:0xB5,0xB1,JAVA程序並不知道這兩個字到底是中文呢?還是日文,或者英文。你如果不指明這個兩個數字的編碼表,JAVA就會按當前系統默認的編碼表來處理。如果這兩個數字是從中文WIN98發出去的,JAVA程序又是在英文LINUX上運行的,那就出現了所謂的亂碼問題了。也就是JAVA按英文的編碼表ASCII來處理這兩個數字,當通過new String({0xB5,0xB1})得到的String的時候,這個String代表的已經不是中文的“當”字,而是兩個英文的奇怪字符了。不過如果你知道這兩個數字一定是中文的話,就可以指定用new String({0xB5,0xB1},"GB2312")來處理,這時候新建立的String才真的是一個“當”字。當然拉,如果你要把一個“當”字的JAVA的String顯示在中文WIN98上,必須把這個字輸出成兩個8位數字:0xB5,0xB1,不管是寫成文件還是輸出到瀏覽器上,都必須是0xB5,0xB1。如何把“當”字用GB2312輸出?String.getBytes("GB2312")就可以拉!所以有一點要記住:和外界交換任何信息都是以byte[]來進行的!。你可以留意一下JAVA大多數的I/O類,都有以byte[]作為參數和返回值的方法。不過,也有很多寫的比較糊塗的程序,沒有提供byte[]交換信息的方法,害的不同文字平臺的程序員很頭疼。Servlet的HttpRequest.getParameter()就是這樣。好在有的JSP/SERVLET容易還提供先指定編碼表的方法,才能比較簡單的解決這個問題。

6. 網上關於JAVA中文問題的一些錯誤處理方法。
一個是最常見的,不管什麽內容,都用new String(...,"ISO-8859-1")來建立字符串,然後使用的時候按默認的編碼格式(通常在服務器上都是英文系統)輸出字符串。這樣其實你使用的String並不是按UNICODE來代表真正的字符,而是強行把BYTE數組復制到String的char[]裏,一旦你的運行環境改變,你就被迫要修改一大堆的代碼。而且也無法在同一個字符串裏處理幾種不同編碼的文字。
另一個是把一種編碼格式的字符串,比如是GB2312,轉換成另一種格式的字符串,比如UTF-8,然後不指明是UTF-8編碼,而直接用new String(...)來建立String,這樣放在String裏面的字符也是無法確定的,它在不同的系統上代表不同的字符。如果要求別人用“UTF-8格式”的String來交換信息的時候,其實已經破壞了JAVA為了兼容各種語言所做的規定。這種錯誤的本質思想是還按寫C語言的方式,把字符串純粹當作可以自己自由編碼的存儲器使用,而忽略了JAVA字符串只有一種編碼格式。如果真的想自由編碼,用byte[]或者char[]就完全了解決問題的了。

以上,除了是解決JAVA中文問題的基礎知識外,也是多年前應該掌握的計算機基礎知識。溫故而知新,以期共勉。

轉:Java中String與byte[]的轉換