事出有因
在向HttpURLConnection的輸出流寫入內容時,因沒有設置charset,致使接收方對數據的驗籤不一致。java
URL url = new URL(requestUrl); //打開鏈接 HttpURLConnection urlConn = (HttpURLConnection)url.openConnection(); ...... ...... //獲取輸出流 out = new OutputStreamWriter(urlConn.getOutputStream()); //發送請求參數 out.write(concatKeyValue(params, false)); out.flush()
回過頭來看,問題看似挺容易解決,只需在獲取輸出流時,指定字符編碼集web
out = new OutputStreamWriter(urlConn.getOutputStream(), "utf-8");
但實則費了一番工夫。期間內心產生了過如下的問題:數據庫
一、String.getBytes(String charset)與String(Byte[] bytes, String charset)的使用。數組
二、什麼場合下會涉及的字符編碼的轉換呢?網絡
三、在不顯示指定charset時,java使用Charset.defaultCharset()來獲取默認字符編碼。Charset.defaultCharset()的值來自哪裏?eclipse
爲了在之後的開發中,快速解決字符集相關問題。在這裏對字符集作了一次比較系統的學習。jvm
字符集與字符編碼
字符是各類文字與符號的總稱,好比語言符號、圖形符號、標點。ide
字符集是字符的集合,每一個字符集包含的字符個數不一樣,常見的字符集有:unicode字符集、ISO 8859字符集、GB2312字符集、GB18030字符集、BIG5字符集等。函數
字符編碼是以二進制數字來對應字符集中的字符,使得計算機可以識別字符集中的字符。學習
各個國家在制定編碼標準的時候,一般是同時制定字符集與編碼規範。所以常見的字符集,如GB2312,除了表示「字符集」這一層含義外,也包含了編碼的含義。
Unicode字符集有多種編碼方式,如UTF-八、UTF-16等;ASCII只有一種;大多數MBCS(Multi-Byte Chactacter System,即多字節字符系統)(包括GB2312)也只有一種。
Java
Java中的字節碼文件始終以unicode編碼方式保存。Java運行時建立的字符串變量、常量等字符串均以unicode編碼存儲在內存中。
當涉及數據讀寫時,就會涉及字符的編碼轉換問題,例如從磁盤讀取文件時、向磁盤寫入文件時、接收網絡發送來的數據時等。
數據存儲到物理介質或經過物理介質傳輸時,都是以bit流的形態存在。而要傳輸正確的bit流,就須要聲明和設置恰當的字符編碼。
getBytes()與getBytes(charset)
當不指定字符集時,getBytes內部會獲取當前操做系統的默認字符集。
getBytes得到字符串的指定編碼規範對應的字節數組,此過程稱爲編碼。
//s的字符編碼方式爲unicode(utf-16), jvm的默認編碼規則 String s = "咱們"; //獲得s的gbk編碼, unicode(utf-16) --> gbk byte[] bytes = s.getBytes("gbk");
String的構造函數String(byte[] bytes, String charset)
//解碼,gbk --> unicode(utf-16) String p = new String(bytes, "gbk");
Charset.defaultCharset()
此方式用來獲取默認字符集,默認字符集在jvm啓動時已經根據系統環境確認,不能夠修改(或者說修改並不會生效)。當jvm的啓動時,也能夠經過參數-Dfile.encoding指定字符集,或經過環境變量修改默認字符集。
另外也請注意咱們運行main方法與web項目的不一樣,它們啓動了jvm的不一樣實例,因此默認字符集可能不一樣。因此若是在main方法中打印Charset.defaultCharset().name()的值 與實際運行web項目時輸入的值不一樣,也不要以爲奇怪。
但凡涉及中文(web開發、I/O、數據庫讀寫等),亂碼問題會與咱們不期而遇,因此理解字符集和字符編碼就頗有必要。
另外:
當咱們使用IDE(idea/eclipse)時,咱們能夠設置開發環境所使用字符集。請注意:IDE中設置的字符集只能表明IDE在存取源代碼文件時使用了何種字符集,而不是class文件使用了何種字符集。