Java中的字符編碼

在平常開發中,常常會遇到關於編碼的問題,讓人總有種弄不清的感受,此次我就整理一下,以便本身複習和你們分享,文中若有錯誤請及時指正。網絡

ASCII編碼

先說說編碼的由來,它的由來再簡單不過了,爲了讓計算機存儲字符。你們知道計算機底層的處理只有二進制,也就是0和1。在沒有計算機的時候,人們使 用8個晶體管來表示狀態和動做,怎麼表示呢?也就是說,每一個晶體管能夠亮或者滅,也就是0和1,根據8個晶體管不一樣的亮滅組合來表示不一樣的意思。那麼根據 數學知識能夠知道,一共有256種組合方式(2的8次方)。編碼

這256種表示一開始並無所有被使用完,只使用了一部分(32個,表示各類狀態),隨着計算機的出現和發展,很快剩下的位置也開始被佔用,用來表 示空格、標點符號、數字、大小寫字符等,一共使用了127個位置,這127個位置所組成的字符對應表,就稱爲ANSII編碼表(American Standard Code for Information Interchange,美國信息互換標準代碼)。簡單來講,ANSII是最原始的計算機編碼表,表示了西方人使用的幾乎全部的經常使用字符。spa

擴展字符集

擴展字符集仍是ASCII編碼表中的,也就是256-127剩下的哪些位置,這些位置存儲了一些更加有意思的字符,好比橫線、豎線交叉等等,也就是擴展後的ASCII碼錶.net

GB2312編碼表

很明顯,隨着世界上愈來愈多的人使用計算機,而本來的ASCII編碼表已經沒有位置了,那麼中國就推出了本身的編碼表,將6000多個經常使用漢字編了 進去。不過對ASCII編碼表作了一些修改:小於127的字符意義與ANSII編碼表同樣,把擴展字符集所有捨棄,兩個大於127的字符連在一塊兒時,就表 示一個漢字。這樣就能夠組合出7000多個漢字,而且還加入了數學符號、羅馬希臘的字母、日文等等,這張碼錶,就是GB2312編碼表。簡單來 說,GB2312編碼表就是ANSII編碼的中文擴展碼錶。code

GBK編碼

不過很快,這張GB2312編碼表也不夠用了,畢竟只有7000多個漢字,而後就繼續擴展,加入了20000多個漢字和符號,就造成了GBK編碼表,GBK包含GB2312的全部編碼orm

GB18030

接着,少數民族的文字也加入了進來,就造成了GB18030編碼表開發

DBCS(Double Byte Charecter Set 雙字節字符集)

以上關於中文的這些編碼表,被統稱爲DBCS,在DBCS系列標準裏,最大的特色是兩字節長的漢字字符和一字節長的英文字符並存於同一套編碼方案 裏,所以程序爲了支持中文處理,必需要注意字串裏的每個字節的值,若是這個值是大於127的,那麼就認爲一個雙字節字符集裏的字符出現了,佔兩個字節, 而小於127的,佔一個字節。get

Unicode

相似中國,全世界的各個國家都開始編寫本身語言的碼錶,這樣就造成了一個混亂的編碼時代,因而乎,就有人要解決這個問題,這個組織就是ISO (國際標誰化組織)。他們的辦法很簡單,廢除全部現存編碼,從新編纂了一套編碼,這套編碼包含全世界全部的字符,這就是Unicode編碼表的由來。爲了 兼容各類字符,規定,Unicode編碼中不論中文英文仍是別的什麼文,每一個字符佔用兩個字節。可是問題也來了,在制定Unicode編碼的時候,沒有考 慮到跟已有任何一種編碼兼容,這使得同一個漢字可能在不一樣碼錶表示的不同,也就是亂碼問題的由來。沒有一種簡單的算術方法能夠把文本內容從 UNICODE編碼和另外一種編碼進行轉換,這種轉換必須經過查表來進行。數學

如前所述,UNICODE 是用兩個字節來表示爲一個字符,他總共能夠組合出65535不一樣的字符,這大概已經能夠覆蓋世界上全部文化的符號。若是還不夠也沒有關係,ISO已經準備 了UCS-4方案,說簡單了就是四個字節來表示一個字符,這樣咱們就能夠組合出21億個不一樣的字符出來。io

UTF-8

什麼是UTF-8呢?簡單來講,UTF-8是一種Unicode編碼表的存儲方式和傳輸標準。它是爲了解決網絡傳輸Unicode編碼而誕生的。來看一張UTF-8實現Unicode存儲的對照表:
UTF-8對照表
從圖中看出,UTF-8編碼實現所佔用的字節數是不肯定的,1到6位都有可能。其實4個字節就幾乎能夠表示全世界的字符了,因此5個字節和6個字節的那種表示方法被停用了。

並且ISO也爲之後作了準備了,指定了UCS-4方案,說簡單了就是四個字節來表示一個字符,這樣咱們就能夠組合出21億個不一樣的字符出來。

中文到底佔幾個字節?

這個問題常常被問到,我是這樣理解的,這個答案要分狀況。若是是DBCS那一套編碼,那麼中文佔兩個字節,若是是UTF-8編碼,中文佔3個字節或 4個字節,至於究竟是3個仍是4個,要看你給的中文在上面那張圖的哪一個區間段中,不一樣的區間段對應的UTF-8格式不同,致使告終果的不一致。

到這裏就差很少了,至於著名的「聯通」亂碼問題我這裏很少說了,開發平時也用不上,有興趣的能夠度娘。

說了這麼多,可能有些混淆了,這裏有個問題,Unicode規定每一個字符佔兩個字節,那麼UTF-8編碼中算幾個呢,中文、英文都分別在不一樣編碼下佔幾個字節?

關於這個問題,仍是那句話,要分狀況,下面用程序來驗證,這是最清楚的方式了:

1 String testStr = "abc";
2 String testCh = "你";
3 System.out.println("GBK編碼:英文長度" + testStr.getBytes("GBK").length);
4 System.out.println("GBK編碼:中文長度" + testCh.getBytes("GBK").length);
5 System.out.println("UTF-8編碼:英文長度" + testStr.getBytes("UTF-8").length);
6 System.out.println("UTF-8編碼:中文長度" + testCh.getBytes("UTF-8").length);
7 System.out.println("Unicode編碼:英文長度" + testStr.getBytes("Unicode").length);
8 System.out.println("Unicode編碼:中文長度" + testCh.getBytes("Unicode").length);

如下爲輸入結果:
運行結果
這 個結果GBK與UTF-8的沒有疑問,Unicode這個結果有點意外,爲何"abc"三個字符會佔8位呢?這個是由於若是你指定要用Unicode來 編碼,Java其實使用的是UTF-16LE來處理,簡單來講,就是這是UTF-16編碼的結果,那麼爲何是8位呢?由於在UTF-16中,不論是中英 日美仍是什麼文,每一個字符都佔兩個字節,那麼"abc"就是6個字節,而爲了通訊,UTF-16須要在字符前面加標識,這個標識叫BOM頭,這個不用管, 只要知道,要加2個字節,因此6 + 2 = 8,就是8個字節,而中文"你"佔2個字節,再加上BOM頭,就是4個字節。那麼就記住,UTF-16中,每一個字符佔兩個字節,總的字符長度 = 字符個數 * 2 + 2,就能夠了。好比中文"你好」,在UTF-16編碼下佔6個字節。

總結一下:

  • 一個英文字符在DBCS編碼體系中,佔一個字節,在UTF-8中佔1個字節,在UTF-16中佔2個字節,可是在UTF-16計算字節數時,要 注意,是總的字符數的兩倍,再加上BOM頭的兩個字節。在Unicode表中,佔兩個字節。Java是基於Unicode編碼的,因此其實Java中的字 符都是兩個字節,可是因爲編碼實現不同,如UTF-8,因此要分清楚這幾種狀況。

  • 一箇中文字符在DBCS編碼體系總,佔兩個字節,在UTF-8中佔3到4個字節(中文在Unicode表中對應的數字從3個字節的格式開始),在UTF-16中佔2個字節,一樣在UTF-16計算字節數時,要注意,是總的字符數的兩倍,再加上BOM頭的兩個字節。

                分享到:

相關文章
相關標籤/搜索