Java開發過程當中亂碼問題理解

一、Java編譯器(即編譯成class文件時) 用的是unicode字符集。
二、亂碼主要是因爲不一樣的字符集相互轉換致使的,理論上各個字符的編碼規則是不一樣的,是不能相互轉換的,因此根本解決亂碼的方法就是不要轉換編碼方式,編碼方式前 後統一。
三、ASCII、GB23十二、GBK、GB18030、Big五、Unicode都是字符集的名稱。它們定義了採用1~2個字節的編碼規範,爲每一個字符賦予了一個獨一無二的編號。這個編號就是咱們所說的「字符編碼」。
四、Unicode字符集定義的字符編碼並不適合直接經過網絡傳輸表達,由於它們必須轉換成像0101這樣的二進制字節流傳輸。因此就出現了不一樣的轉換規範實現方式:UTF-8,TF-16等。這些不一樣的轉換規範轉換後的編碼值和Unicode是不一樣的.(unicode是字符集,編碼實現是utf-8,utf-16等,unicode到utf-8是有算法的,有統一的規則,但unicode和gbk等其餘的編碼方式是沒有直接聯繫的不能轉換)。
五、不要輕易地使用或濫用String類的getBytes(encoding)方法,更要儘可能避免使用getBytes()方法。由於這個方法是平臺依賴的,在平臺不可預知的狀況下徹底可能獲得不一樣的結果。若是必定要進行字節編碼,則用戶要確保encoding的方法就是當初字符串輸入時的encoding(即知道之前的編碼)。
六、http://825635381.iteye.com/blog/2087380(java 默認的Unicode和外部資源編碼的理解)
new String(input.getBytes("ISO-8859-1"), "GB18030")   
上面這段代碼表明什麼?有人會說: 「把input字符串從ISO-8859-1編碼方式轉換成GB18030編碼方式」。若是這種說法正確,那麼又如何解釋咱們剛提到的java字符串都採用unicode編碼呢? 這種說法不只是欠妥的,並且是大錯特錯的,讓咱們一一來分析,其實事實是這樣的:咱們本應該用GB18030的編碼來讀取數據並解碼成字符串,但結果卻採用了ISO-8859-1的編碼,致使生成一個錯誤的字符串。要恢復,就要先把字符串恢復成原始字節數組,而後經過正確的編碼GB18030再次解碼成字符串(即把以GB18030編碼的數據轉成unicode的字符串)。注意,字符串永遠都是unicode編碼的.但編碼轉換並非負負得正那麼簡單,這裏咱們之因此能夠正確地轉換回來,是由於 ISO8859-1 是單字節編碼,因此每一個字節被按照原樣 轉換爲 String ,也就是說,雖然這是一個錯誤的轉換,但編碼沒有改變,因此咱們仍然有機會把編碼轉換回來! java

例子如圖:算法

 import java.io.UnsupportedEncodingException; import java.nio.charset.Charset; public class TestChartCode { public static void main(String args[]) { System.out.println("系統默認字符集 : "+Charset.defaultCharset()); String str = "abc你好";//string with UTF-8 charset 
      
        byte[] bytes = str.getBytes(Charset.forName("UTF-8"));//convert to byte array with UTF-8 encode 
        System.out.println("-------------------將str字符串用UTF-8轉爲字節數組--------------------------"); for (byte b : bytes) { System.out.print(b + " "); } try { System.out.println(); String str1 = new String(bytes, "UTF-8");//to UTF-8 string 
            String str2 = new String(bytes, "ISO-8859-1");//to ISO-8859-1 string 
            String str3 = new String(bytes, "GBK");//to GBK string 
            System.out.println(); System.out.println("-------------------用UTF-8將字節數組轉爲字符串--------------------------"); System.out.println(str1);//abc你好 
            System.out.println("-------------------用ISO-8859-1將字節數組轉爲字符串--------------------------"); System.out.println(str2);//abc?????? 
            System.out.println("-------------------用GBK將字節數組轉爲字符串--------------------------"); System.out.println(str3);//abc浣犲ソ 
            System.out.println(); System.out.println("-------------------1.用ISO-8859-1將亂碼的字符串轉爲字節數組--------------------------"); byte[] bytes2 = str2.getBytes(Charset.forName("ISO-8859-1")); for (byte b : bytes2) { System.out.print(b + " "); } System.out.println(); System.out.println("-------------------2.用ISO-8859-1將亂碼的字符串轉爲字節數組用UTF-8編碼轉字符串--------------------------"); String str22 = new String(bytes2, "UTF-8"); System.out.println(str22);//abc你好 
            System.out.println(); System.out.println("-------------------1.用GBK將亂碼的字符串轉爲字節數組--------------------------"); byte[] bytes3 = str3.getBytes(Charset.forName("GBK")); for (byte b : bytes3) { System.out.print(b + " "); } System.out.println(); System.out.println("-------------------2.用GBK將亂碼的字符串轉爲字節數組用UTF-8編碼轉字符串--------------------------"); String str33 = new String(bytes3, "UTF-8"); System.out.println(str33);//abc你好 
 } catch (UnsupportedEncodingException e){ e.printStackTrace(); } } }

控制檯輸出:數據庫

系統默認字符集 : UTF-8
-------------------將str字符串用UTF-8轉爲字節數組--------------------------
97 98 99 -28 -67 -96 -27 -91 -67 

-------------------用UTF-8將字節數組轉爲字符串-------------------------- abc你好 -------------------用ISO-8859-1將字節數組轉爲字符串-------------------------- abc你好 -------------------用GBK將字節數組轉爲字符串-------------------------- abc浣犲ソ -------------------1.用ISO-8859-1將亂碼的字符串轉爲字節數組--------------------------
97 98 99 -28 -67 -96 -27 -91 -67 
-------------------2.用ISO-8859-1將亂碼的字符串轉爲字節數組用UTF-8編碼轉字符串-------------------------- abc你好 -------------------1.用GBK將亂碼的字符串轉爲字節數組--------------------------
97 98 99 -28 -67 -96 -27 -91 -67 
-------------------2.用GBK將亂碼的字符串轉爲字節數組用UTF-8編碼轉字符串-------------------------- abc你好

總結: 因此,咱們在處理java的編碼問題時,要分清楚三個概念:Java採用的編碼:unicode,JVM平臺默認字符集和外部資源的編碼。數組

七、假如咱們須要從磁盤文件、數據庫記錄、網絡傳輸一些字符,保存到Java的變量中,要經歷由bytes-->encode字符-->Unicode字符的轉換(例如new String(bytes, encode));而要把Java變量保存到文件、數據庫或者經過網絡傳輸,系統要作一個Unicode字符-->encode字符-->bytes的轉換(例如String.getBytes([encode])) 網絡

例子app

package com.bosssoft.platform.appframe.app.controller; import java.io.UnsupportedEncodingException; import java.nio.charset.Charset; public class Test { public static void main(String[] args) throws UnsupportedEncodingException { String str = new String("中文".getBytes("gbk"), "gbk"); System.out.println(Charset.defaultCharset()); System.out.println("----------------中文unicode--->gbk"); printBytes("中文".getBytes("gbk"));//unicode--->gbk 
 System.out.println("----------------中文unicode--->utf8"); printBytes("中文".getBytes("utf8"));//unicode--->utf8 
 str = new String("中文".getBytes("gbk"), "gbk");//unicode---->gbk---->unicode 
 System.out.println("----------------中文unicode---->gbk---->utf8---->unicode---->utf8"); str = new String("中文".getBytes("utf8"), "gbk");//unicode---->gbk---->utf8---->unicode 
        printBytes(str.getBytes("utf8")); str = new String(str.getBytes("gbk"), "utf8"); System.out.println(str); //bytes數組,charset是字節數組安裝什麼方式編碼生成字符串 //new String(bytes, charset) 
          System.out.println(new String(str.getBytes("utf8"), "utf8")); byte[] jvmBytes = str.getBytes("unicode"); System.out.println("jvm Encoding: " + bytesToHexString(jvmBytes)); byte[] defaultBytes = str.getBytes(); System.out.println("page Encoding:" + bytesToHexString(defaultBytes)); byte[] utf8Bytes = str.getBytes("utf8"); System.out.println("uft8: " + bytesToHexString(utf8Bytes)); byte[] gb2312Bytes = str.getBytes("gb2312"); System.out.println("gb2312: " + bytesToHexString(gb2312Bytes)); byte[] gbkBytes = str.getBytes("gbk"); System.out.println("gbk: " + bytesToHexString(gbkBytes)); byte[] gb18030Bytes = str.getBytes("gb18030"); System.out.println("gb18030Bytes: " + bytesToHexString(gb18030Bytes)); byte[] iso8859_1Bytes = str.getBytes("iso8859-1"); System.out.println("iso8859-1: " + bytesToHexString(iso8859_1Bytes)); for(int i=0; i<iso8859_1Bytes.length; i++) { System.out.println(iso8859_1Bytes[i]); } } /** * byte數組轉換成16進制字符串 * @param src * @return */    
    public static String bytesToHexString(byte[] src){ StringBuilder stringBuilder = new StringBuilder(); if (src == null || src.length <= 0) { return null; } for (int i = 0; i < src.length; i++) { int v = src[i] & 0xFF; String hv = Integer.toHexString(v); if (hv.length() < 2) { stringBuilder.append(0); } stringBuilder.append(hv); } return stringBuilder.toString(); } public static void printBytes(byte[] src) { for (byte b : src) { System.out.print(b + " "); } System.out.println(); } } 

八、前面提到從ASCII、GB23十二、GBK到GB18030的編碼方法是向下兼容的。而Unicode只與ASCII兼容(更準確地說,是與ISO-8859-1兼容),與GB碼不兼容。例如「漢」字的Unicode編碼是6C49,而GB碼是BABA。(簡單來講有兩大陣營ANSI和unicode不能相互轉換除了ISO-8859-1,由於他有單字節的特殊性)
九、String name = "我來了";
String str = new String(name.getBytes("x"),"xxx");
無論jvm這裏默認的編碼是GBK仍是UTF-8仍是其餘編碼,name.getBytes("x")java都會自動幫你轉成Unicode編碼,而後再以x的編碼方式轉成xxx的編碼字符集。
例如:如何GbK轉成UTF-8,真正的核心問題是GBK怎麼轉成unicode(沒法直接轉只能找GBK和unicode對照表),轉成unicode之後轉utf-8就好轉了(由於有規律)。java特殊由於java 字符串都是默認unicode的(生產的class文件都是 unicode字符集),因此不管你name.getBytes("xx")是什麼編碼獲得的unicode值都是unicode字符集的正確值。(既然java字符默認都轉成了unicode那麼爲何GBK轉UTF-8爲何仍是亂碼?java都作到默認轉unicode編碼了能夠實現不亂碼了,不知內部爲何?),全部有人在java語言中也有實現GBK轉UTF-8,其實就是直接unicode轉utf-8。jvm

相關文章
相關標籤/搜索