字符集和字符编码的概念区分
字符集和字符編碼的關系,字符集是規范,字符編碼是規范的具體實現;字符集規定了符號和二進制代碼值的唯一對應關系,但是沒有指定具體的存儲方式;
unicode、ASCII、GB2312、GBK都是字符集;其中ASCII、GB2312、GBK既是字符集也是字符編碼;注意不混淆這兩者區別;而unicode的具體實現有UTF-8,UTF-16,UTF-32
最早出現的ASCII碼是使用一個字節(8bit)來規定字符和二進制映射關系,標準ASCII編碼規定了128個字符,在英文的世界,是夠用的。但是中文,日文等其他文字符號怎么映射呢?因此其他更大的字符集出現了
unicode(統一字符集),早期時它使用2個byte表示1個字符,整個字符集可以容納65536個字符。然而仍然不夠用,于是擴展到4個byte表示一個字符,現支持范圍是U+010000~U+10FFFF
unicode是兩個字節的說法是錯誤的;UTF-8是變字長的,需要用14個字節存儲;UTF-16一般是兩個字節(U+0000U+FFFF范圍),如果遇到兩個字節存不下,則用4個字節;而UTF-32是固定四個字節
unicode表示的字符,會用“U+”開頭,后面跟著十六進制的數字,如“字”的編碼就是U+5B57
UTF-8 編碼和unicode字符集
范圍 Unicode(Binary) UTF-8編碼(Binary) UTF-8編碼byte長度 U+0000~U+007F 00000000 00000000 00000000 0XXXXXXX 0XXXXXX 1 U+0080~U+07FF 00000000 00000000 00000YYY YYXXXXXX 110YYYYY 10XXXXXX 2 U+0800~U+FFFF 00000000 00000000 ZZZZYYYY YYXXXXXX 1110ZZZZ 10YYYYYY 10XXXXXX 3 U+010000~U+10FFFF 00000000 000AAAZZ ZZZZYYYY YYXXXXXX 11110AAA 10ZZZZZZ 10YYYYYY 10XXXXXX 4
程序是分內碼和外碼,java的默認編碼是UTF-8,其實指的是外碼;內碼傾向于使用定長碼,和內存對齊一個原理,便于處理。外碼傾向于使用變長碼,變長碼將常用字符編為短編碼,罕見字符編為長編碼,節省存儲空間與傳輸帶寬
JDK8的字符串,是使用char[]來存儲字符的,char是兩個字節大小,其中使用的是UTF-16編碼(內碼)。而unicode規定的中文字符在U+0000~U+FFFF內,因此使用char(UTF-16編碼)存儲中文是不會出現亂碼的
JDK9后,字符串則使用byte[]數組來存儲,因為有一些字符一個char已經存不了,如emoji表情字符,使用字節存儲字符串更容易拓展
JDK9,如果字符串的內容都是ISO-8859-1/Latin-1字符(1個字符1字節),則使用ISO-8859-1/Latin-1編碼存儲字符串,否則使用UTF-16編碼存儲數組(2或4個字節)
System.out.println(Charset.defaultCharset()); //輸出java默認編碼
for (byte item : “程序”.getBytes(StandardCharsets.UTF_16)) {
System.out.print("[" + item + “]”);
}
System.out.println("");
for (byte item : “程序”.getBytes(StandardCharsets.UTF_8)) {
System.out.print("[" + item + “]”);
}
----result----
UTF-8 //java默認編碼UTF-8
[-2][-1][122][11][94][-113] //UTF_16:6個字節?
[-25][-88][-117][-27][-70][-113] //UTF_8:6個字節 正常
“程序”的UTF-16編碼竟是輸出6個字節,多出了兩個字節,這是什么情況?再試試一個字符的輸出
for (byte item : “程”.getBytes(StandardCharsets.UTF_16)) {
System.out.print("[" + item + “]”);
}
—result–
[-2][-1][122][11]
可以看出UTF-16編碼的字節是多了[-2][-1]兩個字節,十六進制是0xFEFF。而它用來標識編碼順序是Big endian還是Little endian。以字符’中’為例,它的unicode十六進制是4E2D,存儲時4E在前,2D在后,就是Big endian;2D在前,4E在后,就是Little endian。FEFF表示存儲采用Big endian,FFFE表示使用Little endian
為什么UTF-8沒有字節序的問題呢?個人看法,因為UTF-8是變長的,由第一個字節的頭部的0、110、1110、11110判斷是否需后續幾個字節組成字符,使用Big endian易讀取處理,反過來不好處理,因此強制用Big endian
其實感覺UTF-16可以強制規定用Big endian;但這其中歷史問題。。。
總結
以上是生活随笔為你收集整理的字符集和字符编码的概念区分的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 乱码问题和字符流
- 下一篇: URI概念的简单介绍