懷疑首先起於這裏:我用 char存儲單個的漢字,可是忽然想到,如何char的範圍僅有0-65535,如何表示全部的漢字(漢字博大精深,已遠超65535個)html
於是我打開eclipse試驗charjava
char ch = (char) 65535; System.out.println(ch);
編譯器不報錯,打印了空(什麼都沒有),估計此處無字符,能夠理解。數組
接下來,我修改成65536eclipse
char ch = (char) 65536; System.out.println(ch);
竟然編譯不報錯,我有點暈了,不是最大65535麼,怎麼大於也行?工具
接下來,我找到一個有漢字的84426編碼
char ch = (char) 84426; System.out.println(ch);
這裏打印出了「䧊」,why?一頭霧水,java官方說明文檔也是指定其是2個byte,16位的無符號值,也即0-65535,why此處84426均可以,並且打印出了「䧊」spa
後來我又增長ch的值,想其難道是4個字節,直到2^31-1=2147483647時,不報錯,加1時2147483648,編譯不經過了,提示以下:.net
char ch = (char) 2147483648;//The literal 2147483648 of type int is out of range System.out.println(ch);
注意裏面的提示The literal 2147483648 of type int is out of range,我才注意到後面的值實際上是int的範圍,因此編譯不報錯,同理long類型的更大,見code
char ch = (char) 0xFFFFFFFFFFFFFFFFL;//0x表示16進制,後面的L標明爲long類型
因此編譯不報錯,指的是未超事後面類型的範圍,因此不報錯。htm
那麼既然這麼大,char範圍0-65535那麼小,是否有轉換規則,是的,見下面
也就是大於65535的int值賦予char時,其會自動mod 65536(此處只針對大於,小於的話就不對了,見下),得出65535範圍內的一個unicode
int i = 18890 + 65536; //大於65535即mod,此處加了好幾個65535,其仍是表明18890 //int i = 18890 + 65536 + 65536 + 65536; //int i = 18890 - 65536 - 65536; char c = (char)i; System.out.println(c); //mod針對大於65535的還好使,可是其表明的是這個意思 System.out.println(i % 65536); //Integer.valueOf()能獲得其表明的unicode值的大小,十進制int表示 System.out.println(Integer.valueOf(c)); char d = '䧊'; int n = (int)d; System.out.println(n);
由上可見,其實「䧊」字的unicode碼是18890,而非84426,而且其範圍超過0-65535的範圍,若是強制轉換(char c = (char)i;)java會根據規則自動轉換到0-65535區間中的一個。
到這裏估計也就明白了,是本身寫錯了,下面這種方式確定會提示編譯錯誤的
char ch = 65536;// Type mismatch: cannot convert from int to char
也即char的範圍的確是0-65535。其實char單引號的寫法(
char ch = '䧊';
),只是爲了方便記憶和書寫,它仍是會轉爲數字碼的形式,也即unicode碼存儲。
那到了這裏
疑問還在,那就是65535的範圍如何存儲那麼多的漢字?
答案是其存不了那麼多,最多隻能是65535,由於在此範圍以外的都會轉換到此範圍裏
並且我試了找到65535以外的漢字(用此工具查看UniToy)來試驗,但是始終沒法打出這些漢字,遂放棄了
大於65535的漢字,截取一部分
還有點疑問:看下面
public class Test { public static void main(String[] args) { String str= "中"; char x ='中'; byte[] bytes=null; byte[] bytes1=null; byte[] bytes2=null; try { bytes = str.getBytes("gbk"); bytes1 = str.getBytes("utf-8"); bytes2 = charToByte(x); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } System.out.println("bytes 大小:"+bytes.length); System.out.println("bytes1大小:"+bytes1.length); System.out.println("char轉換爲byte數組大小:"+bytes2.length); System.out.println("byte數組的兩個值,其實unicode值的兩個字節拆分到數組裏了:"+bytes2[0]+"-"+bytes2[1]); } // 如「中」的unicode值爲Integer.valueOf(x)=20013 // 二進制爲0100 1110 0010 1101 // 拆分出來即爲b[0]=0100 1110 b[1]=0010 1101 public static byte[] charToByte(char c) { byte[] b = new byte[2]; b[0] = (byte) ((c & 0xFF00) >> 8); b[1] = (byte) (c & 0xFF); return b; } }
輸出:
gbk byte數組大小:2
utf8 byte數組大小:3
char轉換爲byte數組大小:2
byte數組的兩個值,其實unicode值的兩個字節拆分到數組裏了:78-45
java是用unicode來表示字符,"中"這個中文字符的unicode就是2個字節。
String.getBytes(encoding)方法僅是獲取指定編碼的byte數組表示,而非java char存儲時會佔3個字節,只是utf8編碼時該佔幾個字節
一般gbk/gb2312是2個字節,utf-8是3個字節。
若是不指定encoding則取系統默認的encoding。
-----------------------------------------------------------------------------------------------------------
另UTF-8,GBK等這裏沒涉及,他們只是編解碼規則,按必定規則編解碼,再和其對應的字符圖案對應起來。
其實簡單來講UTF-8就是unicode碼如何轉換爲字符來顯示的,其有必定的轉換規則,具體見http://my.oschina.net/u/914655/blog/318738處第11項。
另目前漢字範圍及與unicode如何對應
GB2312有6763個漢字,GBK有21003個漢字,GB18030-2000有27533個漢字,GB18030-2005有70244個漢字。
Unicode 5.0中,若是不算兼容區,目前有70217個漢字。讓咱們比較一下Unicode的70217漢字和GB18030-2005中的70244漢字:
GB18030-2005 | Unicode 5.0 | 對應的Unicode編碼 |
CJK統一漢字的20902漢字 | CJK統一漢字的20902漢字 | 0x4E00-0x9FA5 |
CJK統一漢字擴充A的6582漢字 | CJK統一漢字擴充A的6582漢字 | 0x3400-0x4DB5 |
CJK統一漢字擴充B的42711漢字 | CJK統一漢字擴充B的42711漢字 | 0x20000-0x2A6D6 |
CJK部首補充區的14個部首 | 未計入 | 2E81, 2E84, 2E88, 2E8B, 2E8C, 2E97, 2EA7, 2EAA, 2EAE, 2EB3, 2EB6, 2EB7, 2EBB, 2ECA |
CJK兼容漢字區的21個漢字 | 未計入 | F92C, F979, F995, F9E7, F9F1, FA0C, FA0D, FA0E, FA0F, FA11, FA13, FA14, FA18, FA1F, FA20, FA21, FA23, FA24, FA27, FA28, FA29 |
![]() |
CJK統一漢字區新增了這8個字符 | 0x9FB4-0x9FBB |
未計入 | CJK統一漢字區新增的14個字符 | 0x9FA6-0x9FB3 |