Java中char和String 的深刻理解 - 字符編碼

開篇

https://blog.csdn.net/weixin_37703598/article/details/80679376html

 

咱們並非在寫代碼,咱們只是將本身的思想經過代碼表達出來!java

1 將思惟變現成爲一行代碼,是從抽象思惟到具體代碼的編碼過程;繼而計算機再將咱們的代碼再解碼爲計算機能處理的形式--2進制數字。程序員

2 當計算機須要向你展現數據時它還須要將2進制數字參照必定的規則(碼錶)編碼爲人所能理解的格式。算法

 

若是不能清楚的理解編碼和解碼的原理和規則,我想做爲程序猿的你是必定會善罷甘休的吧。哈哈,請隨個人思路一塊兒,讓咱們知其因此然吧!數據庫

咱們這裏只討論狹義的計算機字符編碼問題,如下論述都是基於此條件之下,才疏學淺,若有錯誤請同窗們不吝賜教哦。數組

 

字符編碼瀏覽器

 

1 總論服務器

What/定義:編碼是信息從一種形式或格式轉換爲另外一種形式的過程,而解碼是其逆過程。數據結構

Why/爲何須要編碼:見開篇。編碼

How/怎麼編碼:人們發明了不少碼錶,編碼和解碼實際上就是在查不一樣的碼錶(好像字典)的過程。

 

2 碼錶

2.1 祖宗:ASCII(American Standard Code for Information Interchange,美國標準信息交換代碼),這是個單字節編碼表,它能最多能表示256個字符(但實際上只用了7bit,128個。ISO8859-1使用8bit來表示,能表示256)。

(引用百度百科的圖片,侵刪)

2.2 Unicode

Unicode/UCS 是及其重要,以致於我要啓用最大的標題來描述它!
 
1 歷史到今天

1 隨着時間的發展,其它語言的人民也須要使用計算機,也須要編碼本身的語言,不少國家和地區就各自使用了2個字節來表示本身的文字編碼,如GBK、BIG5等。這種方式固然會形成不一樣語言編碼和解碼的混亂和錯誤,人們意識到須要一個統一的碼錶來囊括世界上全部的字符,從而實現編碼的統一。

2 九十年代左右有兩個組織分別作了兩個碼錶要作統一,ISO的UCS 10646(Universal Character Set,UCS)和統一碼聯盟的Unicode。
但咱們不須要兩個不兼容的統一字符集,在1991年先後,他們終於聯合起來共同維護一個標準了(他們仍是各自發展,但字符集統一),從Unicode2.0開始,採用與ISO10646-1相同的字庫和字碼。二者目前兼容發展着。

3 UCS和Unicode使用最大32bit來表示字符,能夠表示42億個字符(4,294,967,296),目前只使用了1,114,112個碼位,從0x0~0x10FFFF。
它們爲了和不一樣的區域性字符集相互兼容,把其首256字符使用ISO8859-1所定義的字符,並把大量字符重複編到不一樣的字符碼位置,從而使得舊有的紛繁複雜的編碼方式得以和Unicode編碼直接互相轉換,而不會丟失任何信息。
(摘抄自其它資料,這點我存疑:事實上我發現它只向下兼容8859-1,而且只有使用UTF-8轉換格式時才行,直接使用Unicode==UTF-16仍是錯誤結果。錯誤緣由在下邊UTF那有描述)

4 UCS-4爲4字節,它根據最高位爲0的最高那1個字節,表示出2的7次方128個group,而後每一個group根據此高字節分爲256個plane,每一個plane根據根據第3個字節分爲256個row,每row有256個cell。group 0的plane 0 稱爲BMP(Basic Multilingual Plane)。
若是UCS-4的前2個字節全零(也就是用了plane 0),那麼將UCS-4的BMP去掉前兩個0字節就獲得了UCS-2.
[html]  view plain  copy
 
 
 
 
  1. 128group  256plane   256 row   256 cell  
  2. 0000 0000,0000 0000,0000 0000,0000 0000  

5 Unicode計劃使用17個平面,一共有17*65535=1,114,112個碼位。在Unicode5.0中,已定義的碼位只有238,605個,分佈在plane0,1,2,14,15,16中。15,16只是定義了65534個碼位專用區(Private Use Area),分別是0xF0000~0xFFFFD和0x100000~0x10FFFD。專用區PUA:留給你們放自定義字符的區域。
plane 0也有一個專用區:0xE000~0xF8FF,共6400個碼位。它還有代理區(Surrogate)0xD800~0xDFFF(55296~57343),共2048個碼位。代理區的目的是:用兩個UTF-16字符表示BMP以外的字符。
238605-65535*2-6400-2048=99,089。這9萬多個字符定義在plane 0(52080),1(3419),2(43253),14(337)上。有71,226個漢字,plane 2的43253都是漢字,plane0上定義了27973個漢字。
 
6 Unicode3.1開始使用輔助plane,2015年6月17號Unicode發佈8.0 目前的Unicode碼錶區段
0000..007F;   Basic   Latin    
0080..00FF;   Latin-1   Supplement    
0100..017F;   Latin   Extended-A    
0180..024F;   Latin   Extended-B    
0250..02AF;   IPA   Extensions    
02B0..02FF;   Spacing   Modifier   Letters    
0300..036F;   Combining   Diacritical   Marks    
0370..03FF;   Greek    
0400..04FF;   Cyrillic    
0530..058F;   Armenian    
0590..05FF;   Hebrew    
0600..06FF;   Arabic    
0700..074F;   Syriac        
0780..07BF;   Thaana    
0900..097F;   Devanagari    
0980..09FF;   Bengali    
0A00..0A7F;   Gurmukhi    
0A80..0AFF;   Gujarati    
0B00..0B7F;   Oriya    
0B80..0BFF;   Tamil    
0C00..0C7F;   Telugu    
0C80..0CFF;   Kannada    
0D00..0D7F;   Malayalam    
0D80..0DFF;   Sinhala    
0E00..0E7F;   Thai    
0E80..0EFF;   Lao    
0F00..0FFF;   Tibetan    
1000..109F;   Myanmar      
10A0..10FF;   Georgian    
1100..11FF;   Hangul   Jamo    
1200..137F;   Ethiopic    
13A0..13FF;   Cherokee    
1400..167F;   Unified   Canadian   Aboriginal   Syllabics    
1680..169F;   Ogham    
16A0..16FF;   Runic    
1780..17FF;   Khmer    
1800..18AF;   Mongolian    
1E00..1EFF;   Latin   Extended   Additional    
1F00..1FFF;   Greek   Extended    
2000..206F;   General   Punctuation    
2070..209F;   Superscripts   and   Subscripts    
20A0..20CF;   Currency   Symbols    
20D0..20FF;   Combining   Marks   for   Symbols    
2100..214F;   Letterlike   Symbols    
2150..218F;   Number   Forms    
2190..21FF;   Arrows    
2200..22FF;   Mathematical   Operators    
2300..23FF;   Miscellaneous   Technical    
2400..243F;   Control   Pictures    
2440..245F;   Optical   Character   Recognition    
2460..24FF;   Enclosed   Alphanumerics    
2500..257F;   Box   Drawing    
2580..259F;   Block   Elements    
25A0..25FF;   Geometric   Shapes    
2600..26FF;   Miscellaneous   Symbols    
2700..27BF;   Dingbats    
2800..28FF;   Braille   Patterns    
2E80..2EFF;   CJK   Radicals   Supplement    
2F00..2FDF;   Kangxi   Radicals    
2FF0..2FFF;   Ideographic   Description   Characters    
3000..303F;   CJK   Symbols   and   Punctuation    
3040..309F;   Hiragana(日文平假名)  
30A0..30FF;   Katakana(日文片假名)  
3100..312F;   Bopomofo    
3130..318F;   Hangul   Compatibility   Jamo    
3190..319F;   Kanbun    
31A0..31BF;   Bopomofo   Extended    
3200..32FF;   Enclosed   CJK   Letters   and   Months    
3300..33FF;   CJK   Compatibility    
3400..4DB5;   CJK   Unified   Ideographs   Extension   A    
4E00..9FFF;   CJK   Unified   Ideographs    
A000..A48F;   Yi   Syllables    
A490..A4CF;   Yi   Radicals    
AC00..D7A3;   Hangul   Syllables    
D800..DB7F;   High   Surrogates    
DB80..DBFF;   High   Private   Use   Surrogates    
DC00..DFFF;   Low   Surrogates    
E000..F8FF;   Private   Use    
F900..FAFF;   CJK   Compatibility   Ideographs    
FB00..FB4F;   Alphabetic   Presentation   Forms    
FB50..FDFF;   Arabic   Presentation   Forms-A    
FE20..FE2F;   Combining   Half   Marks    
FE30..FE4F;   CJK   Compatibility   Forms    
FE50..FE6F;   Small   Form   Variants    
FE70..FEFE;   Arabic   Presentation   Forms-B    
FEFF..FEFF;   Specials    
FF00..FFEF;   Halfwidth   and   Fullwidth   Forms    
FFF0..FFFD;   Specials   
10300..1032F;   Old   Italic 10330..1034F;   Gothic    
10400..1044F;   Deseret    
1D000..1D0FF;   Byzantine   Musical   Symbols    
1D100..1D1FF;   Musical   Symbols    
1D400..1D7FF;   Mathematical   Alphanumeric   Symbols    
20000..2A6D6;   CJK   Unified   Ideographs   Extension   B    
2F800..2FA1F;   CJK   Compatibility   Ideographs   Supplement    
E0000..E007F;   Tags    
F0000..FFFFD;   Private   Use    
100000..10FFFD;   Private   Use  

最經常使用的CJK(Chinese Japanese Korean 中日韓文)區間段是4E00~9FFF,但9FA6~9FFF仍是空的,因此實際有值得是4E00~9FA5,這也是大部分人判斷中文所用的區段。但你們要知道,其實CJK大部分是描述的中文,日文和韓文還有相應的區間。上表中帶有CJK的、平假名Hiragana、片假名Katakana、朝鮮文Hangul的都是中日韓文可能的字符區間:

CJK   Unified   Ideographs  

只是經常使用的區間,所有CJK區間應該是:

2E80..2EFF(11904-12031): CJK   Radicals   Supplement    
3000..303F(12288-12351): CJK   Symbols   and   Punctuation  
3040..309F(12352-12447): Hiragana(日文平假名)  
30A0..30FF(12448-12543): Katakana(日文片假名)  
3130..318F(12592-12687): Hangul Compatibility Jamo(朝鮮文兼容字母)  
31F0..31FF(12784-12799): Katakana Phonetic Extensions(日文片假名語音括展)  
3200..32FF(12800-13055): Enclosed CJK Letters and Months   
3300..33FF(13056-13311): CJK Compatibility   
3400..4DB5(13312-19893): CJK Unified Ideographs Extension A   
4E00..9FFF(19968-40959): CJK Unified Ideographs  
AC00..D7AF(44032-55215): Hangul Syllables(朝鮮文音節)     
F900..FAFF(63744-64255): CJK Compatibility Ideographs   
FE30..FE4F(65072-65103): CJK Compatibility Forms   
20000..2A6D6(131072-173782): CJK Unified Ideographs Extension B   
2F800..2FA1F(194560-195103): CJK Compatibility Ideographs Supplement  
 
-----------------------------------------------------------------------------------------------------------
 
Unicode/UCS總結:
也就是說它用2~4個字節的空間描述了已知的接近所有的字符(而且仍在更新,還會把笑臉之類的字符 大笑也放入其中),而一般使用的plane 0也就是UCS-2,使用2個字節描述了比較經常使用的字符,包括大量的CJK文字,因此你們日常能用到的字符大致都在UCS-2中包括了。
 
2 UTF
 
1 UTF(UCS/Unicode/Universal Transformation Format)有多種transform方式,常見的有UTF-8/UTF-16/UTF-32。出現緣由:
a:事實證實,對可使用ASCII表示的字符使用Unicode並不高效,由於Unicode使用2個字節。爲了解決這個問題,出現了一些中間格式字符集,被稱爲通用轉換格式。能夠這麼說Unicode是編碼方式,它規定了編碼(即哪一個字符在什麼碼位),而UTF-8等是Unicode的實現方式,它出於節省空間或其它目的來對Unicode所佔空間進行轉換。
b:另外我目前的理解是:Unicode碼原生不支持與任何碼錶兼容,包括ASCII。
舉例:UCS-2以2字節爲單位而ASCII以1個字節爲單位,試想英文a,0110,0001和0000,0000 0110,0001計算機是不會認爲他們是同樣的。而若是使用UTF-8那麼,編碼就會相同爲1個字節0110,0001。
 
2 UTF-8(將8bit看做一個單位):使用1~4個字節來編碼,如,當時用UTF-8存儲ASCII字符時就只用1個字節,類似其它字符按必定算法轉換爲1~4個字節。算法以下
UCS-2編碼(16進制) UTF-8 字節流(二進制)   
0000 - 007F 0xxxxxxx   
0080 - 07FF 110xxxxx 10xxxxxx   
0800 - FFFF 1110xxxx 10xxxxxx 10xxxxxx  
好比「漢」字的Unicode是6C49,那麼就須要使用3字節的格式,寫出來是1110 0110,1011 0001,1000 1001,也即E6 B1 89。4字節算法沒寫。

3 UTF-16
3.1 將16bit看做一個單位。設計之初爲固定寬度的16bit(2byte)編碼格式(能夠表示plane 0全部),隨着時間發展爲了支持增補字符(其它plane)設置了代理對機制(surrogate pair);把範圍U+10,0000~U+10,FFFF內的字符使用一對(2個)16bit來表示。
算法以下:對於的UCS碼的小於0x10000的部分(plane 0中的),UTF-16編碼==UCS-2對應的16位無符號整數。不小於0x10000的部分使用代理對(具體怎麼代理不探究了)。
 
3.2 UCS-2是一個編碼方案,而UTF-16是一個實際使用的轉換格式。由於UTF-16一個單元是16bit,但計算機只能表示8bit爲單位,因此分解(解析顯示時)這個單元時這兩個8bit誰先誰後就也有說法了(即一個單位中2個字節的字節順序問題),高字節到低字節稱爲大尾big-endian,反之稱爲小尾little-endian。UTF-32也須要考慮這個問題,而UTF-8已8bit爲單位,故而沒有在單位中排字節順序的須要。
 
例如:已知「乙」的Unicode編碼是4E 59,當咱們收到一個「奎」的Unicode編碼59 4E時,咱們是該翻譯爲奎仍是乙呢?
解決方案:
使用Unicode的推薦字節順序標記方法BOM(Byte Order Mark)。  
它的方法是:UCS中有個字符叫"ZERO WIDTH NO-BREAK SPACE",它編碼爲FE FF,還有個字符FF FE在UCS中不存在。  
UCS規範建議咱們在傳輸字節流最前,先傳輸字符FE FF代表字節流是Big-Endian;傳輸FF FE代表字節流是Little-Endian。  
UTF-8不須要用BOM來代表字節順序,可是能夠用BOM來代表編碼方式。字符"ZERO WIDTH NO-BREAK SPACE"的UTF-8編碼是EF BB BF。若是接受到已此開頭的字節流,那麼好了,你知道它是UTF-8編碼的。
 
「你好」的Unicode編碼:4F 60 , 59 7D
下圖是用UTF-8編碼的文本:「你好」兩個字的編碼。
使用UTF-16 Big-endian的「你好」
 
3.3 比起UTF-8,16的好處在於大部分字符都是用固定長度(2byte)存儲(若是長度固定是你的要求的話)。
 

2.3 中國

GB GB2312 GBK 是國標以及其擴展碼錶。佔用雙字節。

BIG5是臺灣/香港使用的繁體字符集。

GBK整體範圍爲:0x8140~0xFEFE,首字母在0x81~0xFE之間,尾字節在0x40~0xFE之間,剔除0x**7F一條線,總計23940個碼位,收入21886個漢字(21003)和圖形符號(883)。

 
實際應用
 
1 全部瀏覽器或客戶端使用http協議請求一個資源時,資源的響應通常都會有個Content-Type來表示服務器資源的類型,瀏覽器/客戶端根據此來對照相應碼錶解碼顯示。注意:有時候服務器不返回這個字段,那麼大部分瀏覽器會相應的規則去本身算應該用哪一個編碼來顯示(我並不清楚,大概是有BOM就按照使用對應UTF格式,無BOM使用ISO-8859-1吧?)。
 
2 考慮到國際化的軟件發展趨勢,建議不要使用GB家族的編碼。
 
3 傳輸UTF編碼字節流時,使用BOM;

 

 

JAVA

好了,我是Java程序員,我只爲了理解《Tinking in java》中的一句話才搞了一天時間來研究這個問題的,好在仍是有點成果!!

「java中有個基本類型char,它佔用固定的2byte空間來表示字符,又由於java設計之初就採用了Unicode編碼,因此char能表示全部字符包括中文。」

看到滿世界這樣的答案,我就不相信了!2字節最多隻能標識65536個字符,它是怎麼能囊括那麼多字符的呢??僅全部漢字就不止6萬吧!!!!

 

好了,無論你看沒看完上邊的文章,我告訴你結論就好!

結論

 

1. char

java中的char確實使用2Byte空間,它實際使用的是UCS-2 也就是plane 0,只能表述65536個字符,對於超出其範圍的其它plane內容,請看下圖:

一旦你使用了大於UCS-2的字符,那麼編譯器會直接報錯!

其實也就是說char使用的是UTF-16格式。有個建議是儘可能別用char類型,由於它會致使一些隱蔽的錯誤。好比,當你在用String時你定義了一個「蟲」,你想固然的認爲一個char就能盛放String中的一個字符(畢竟char是字符,而String就是描述的char數組),可是你會發現其實這個String的length()是2而不是1,由於它超出了UCS-2,String用兩個char的位置(4字節)來表示了這個char,而String本該用一個char的位置來表示它纔對。

2. String

首先,String可以支持的字符與你寫代碼時選擇的編碼方式有關,當你選擇UTF編碼時,你能夠隨便使用Unicode字符,用沒腳」蟲「當變量名都隨你。使用GB*時,沒腳蟲」蟲「不被支持(GBK收錄的少一些吧或者這是日本字吧?)

其次,String在Java中是被定義爲char數組來組織的,因此你定義的String最終要被轉換成char來存放,可是,不要認爲超出char的65536就不能存了,若是超出了它會用2個char來存放

在這裏我想用兩種方向來講1個String佔用的空間

1. 在Java中實際使用的空間

這與使用的編碼有關

UTF-8:2/4byte,其實就是1個char或者2個char;

GB*:2byte,就是1個char;

 

2. 若是對其編碼,所須要的空間(String.getBytes())

UTF-8:1~4byte,ASCII用1Byte,漢字大部分用3Byte,其它字符參照上邊UTF2.2的算法,超出UCS-2的部分好比那個「蟲」就會是4Byte;

GB*:ASCII使用1Byte,其它中文2Byte;

 

3. 額外的部分---從java到class文件

不管.java文件你用GBK或者UTF-8來編碼,編譯器在將其編譯爲.class文件後,若是其中有字符串,會使用UTF-8來編碼存儲字節,佔用1-4Byte。詳細來講,就是在.class文件的常量池部分,這種字符串數據使用的數據結構是CONSTANT_Utf8_info,表明UTF-8編碼的字符串。

 

最後吐槽一下!!!我打了3遍才把發佈好這最後一段,一旦我打了那個少一腿的」蟲「字,我後邊的東西就被吃了,是保存到數據庫時直接給我後邊的忽視了嗎???

相關文章
相關標籤/搜索