疑問1:java char範圍0-65535,如何存儲那麼多漢字

懷疑首先起於這裏我用 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
8個部首 CJK統一漢字區新增了這8個字符 0x9FB4-0x9FBB
未計入 CJK統一漢字區新增的14個字符 0x9FA6-0x9FB3
相關文章
相關標籤/搜索