1、引言java
平常複習總結,發現過久不看基礎,不少概念的東西仍是給忘了,本文將教你如何快速區分「字符」與「字符集」。windows
2、基礎知識數組
各類文字和符號的總稱,包括各國家文字、標點符號、圖形符號、數字等。 也就是說,它是一個信息單位,一個數字是一個字符,一個文字是一個字符,一個標點符號也是一個字符。tomcat
字節是一個8bit的存儲單元,取值範圍是0x00~0xFF。 根據字符編碼的不一樣,一個字符能夠是單個字節的,也能夠是多個字節的。jvm
字符的集合就叫字符集。不一樣集合支持的字符範圍天然也不同,譬如ASCII只支持英文,GB18030支持中文等等。編碼
在字符集中,有一個碼錶的存在,每個字符在各自的字符集中對應着一個惟一的碼。可是同一個字符在不一樣字符集中的碼是不同的,譬如字符「中」在Unicode和GB18030中就分別對應着不一樣的碼(20013
與54992
)。spa
簡單來講,字符集就是一個按規則排列的字符的集合,能夠理解爲現實生活中的各類「字典」。例如:牛津字典,劍橋商務字典等等。同一個「單詞」在不一樣的字典中的位置是不一樣的,同理也不是全部的字典都支持各類語言的,例如ASCLL字符集裏面就沒有中文。code
定義字符集中的字符如何編碼爲特定的二進制數,以便在計算機中存儲(就是將字符在字符集中的對應位置化爲二進制)。字符集和字符編碼通常一一對應(也有例外)blog
字符集與字符編碼的一個例外就是Unicode字符集,它有多種編碼實現(UTF-8,UTF-16,UTF-32等)內存
3、舉例理解
其實經過上面的標藍的句子相信你們已經有了區分的理解。下面再舉出一些例子,來加深你們的理解:
ASCII碼是一個字符集,同時它的實現也只有一種,所以它也能夠指代這個字符集對應的字符編碼。
GB18030是一個字符集,主要是中國人爲了解決中文而發明制定的,因爲它的實現也只有一種,因此它也能夠指代這個字符集對應的字符編碼。
Unicode是一個字符集(java默認),爲了解決不一樣字符集碼錶不一致而推出的,統一了全部字符對應的碼,所以在這個規範下,全部字符對應的碼都是一致的(統一碼),可是統一碼只規定了字符與碼錶的一一對應關係,卻沒有規定該如何實現,所以這個字符集有多種實現方式(UTF-8,UTF-18,UTF-32),所以這些實現就是對應的字符編碼。 也就是說,Unicode統一約定了字符與碼錶直接一一對應的關係,而UTF-8是Unicode字符集的一種字符編碼實現方式,它規定了字符該如何編碼成二進制,存儲在計算機中。
附:經常使用編碼表
ISO8859-1 | GBK/GBK2312 | UTF-8 | UTF-16 | UTF-32 | |
英文字符 | 1字節 | 2字節 | 大部分3,少部分4 | 2字節 | 4字節 |
中文字符 | 1字節 | 1字節 | 1字節 | 2字節 | 4字節 |
如表所示,ISO8859-一、utf-1六、utf-32都是定長字符編碼,其中utf-16(Unicode)更是jvm默認的內碼編碼。
內碼 vs 外碼
java在內部都是unicode編碼,不存在什麼GBK/UTF-8只有在輸入輸出的時候,纔會發生與外部的編碼轉化問題。
簡單來講,內碼:char或String在內存裏使用的編碼方式。
外碼:除了內碼均可以認爲是「外碼」。(包括class文件的編碼)
java內碼:unicode(utf-16)
jvm默認外碼:windows——gbk
Linux——utf-8
外碼操做:
[String].getBytes() 就是將內碼轉換成外碼存儲在byte數組裏,方法有兩種形式:
getBytes(String charsetName): 使用指定的字符集將字符串編碼爲 byte 序列,並將結果存儲到一個新的 byte 數組中。
getBytes(): 使用平臺的默認字符集將字符串編碼爲 byte 序列,並將結果存儲到一個新的 byte 數組中。
new String(byte[] bytes, String charset): 將字符序列bytes使用「charset」的字符編碼(外碼),解碼成字符串(內碼)。
編碼和解碼的「字符編碼」必需要一致才能解碼成想要的字符串(英文例外)。
可是爲何在tomcat 下,使用 new String(s.getBytes("iso-8859-1") ,"GBK") 卻能夠用呢? 答案是:
tomcat 默認使用iso-8859-1編碼, 也就是說,若是本來字符串 str 是GBK的,tomcat傳輸過程當中,將GBK轉成iso-8859-1編碼的字符數組了,至關於:
String s = "中國";
byte[] str_bytes = s.getBytes("GBK"); // 底層操做1:jvm,此時編碼格式爲gbk; String s = new String(str_bytes, "iso-8859-1"); // 底層操做2:tomcat; String str_new =new String(s.getBytes( "iso-8859-1"), "gbk"); // 獲得正確字符串
默認狀況下,使用iso-8859-1讀取中文確定是有問題的,那麼咱們須要將iso-8859-1 再轉成GBK, 而iso-8859-1 是單字節編碼的,即他認爲一個字節是一個字符, 那麼這種轉換不會對原來的字節數組作任何改變,由於字節數組原本就是由單個字節組成的,若是以前用GBK編碼,那麼轉成iso-8859-1後編碼內容徹底沒變, 則 s.getBytes("iso-8859-1") 實際上仍是原來GBK的編碼內容則 new String(s.getBytes("iso-8859-1") ,"GBK") 就能夠正確解碼了。 因此說這是一種特殊狀況。