溫馨提示: 本文大約5097字,閱讀完大概需要3-5分鐘,希望您能耐心看完,倘若你對該知識點已經比較熟悉,你可以直接跳轉到你感興趣的地方,希望閱讀本文能夠對您有所幫助,如果閱讀過程中有什么好的建議、看法,歡迎在文章下方留言或者私信我,您的意見對我非常寶貴,再次感謝你閱讀本文。
一: 編碼江湖之初恩怨
在編碼的江湖中,"亂碼"算得上我們遇到的最難纏的"敵人"之一,一旦遇上、輕則心情煩躁、重則心態崩潰。文章開頭,讓我們再次重溫與"亂碼"初見面的名場面。
String str = "亂碼,你好";
byte[] bytes = str.getBytes("GBK");
String string = new String(bytes,"UTF-8");
System.out.println(string);
運行結果:

是不是感覺很熟悉,這個是出現亂碼最簡單的例子,雖然在編程時我們肯定不會這樣寫,但是,亂碼出現的原因都是相通的,想要知道為什么?那就繼續我們的"亂碼"江湖的闖蕩吧。
二: 編碼江湖之"亂碼"家族
想要從根本上鏟除"亂碼"這個敵人,我們就必須對它的生命歷程有清楚的認識,正所謂:"知己知彼,才能百戰不殆"。
(一)"亂碼"產生的原因:
在編碼江湖中,我們想要生存下來,首先得懂得這個江湖的規則,計算機就是我們闖蕩的編碼江湖,但是,計算機的規則約定: 它們只能夠讀懂二進制數0和1,我們能夠表達的確實對應的字符,為了在編碼程序中生存下來,我們需要一種技術能夠將我們表達的字符轉換成對應計算機能夠讀懂的二進制數0和1,這種技術就叫編碼,但是,因為闖蕩這者的不同,所表達的字符就存在差異,所以針對不同的闖蕩地區,存在不同的編碼,如果不是同一個地區使用了其他地區的編碼方式進行轉換,就會出現"亂碼",計算機就會看不懂。
三: 江湖規則之基礎知識
想要在計算機世界行走江湖,就必須對這個世界的基礎概念有個清晰的認識,下面就講解關于計算機世界的基礎知識講解:
Bit(位)
計算機世界的最小存儲單位,也是計算機能夠讀懂的,可取的值是0或1,每個值就標識1位,如:0000 0001表示的就是8位,轉換成我們認識的數值(十進制)就是1。
Byte(字節)
計算機世界中的一種表示存儲容量的單位,1Byte = 8Bit,即一個字節可以存儲8位,除了Byte外,計算機還有以下常用的存儲容量單位以及他們之間的轉換關系:
1Byte = 8bit
1KB(KByte) = 1024Byte = (1024 * 8)bit
1MB(MByte) = 1024KB =(1024 * 1024)Byte = (1024 * 1024 * 8)bit
1GB = 1024MB = (1024 * 1024)KB =(1024 * 1024 * 1024)Byte = (1024 * 1024 * 8)bit
1T = 1024GB = (1024 * 1024)MB = (1024 * 1024 * 1024)KB =(1024 * 1024 * 1024 * 1024)Byte = (1024 * 1024 * 1024 * 8)bit
字符
字符也就是我們在計算機表達的"語言",常見的包括:數值、字母、文字和符號,如:1、a、A、試、$...都表示的是一個字符,在計算機世界中,不同的字符可能需要不同的存儲容量進行存儲。
字符集
集:表示集合,字符集則表示多個字符的集合,每個字符集可以包括不同的字符,常見的字符集如下:
ASCII字符集
GB2312字符集
Unicode字符集
字符編碼
定義: 將字符集中的字符編碼(映射)成集合中的某一個對象如:比特模式、自然數序列、電脈沖等,以方便字符在計算機中存儲和在計算機網絡中傳遞
字符集與字符編碼的區別
字符集表示:多個字符的集合,字符編碼則是:將字符集中的字符映射為特定的字節或者字節序列,它表示的是一種規則。通常特定的字符集采用特定的編碼方式(即一種字符集對應一種字符編碼,如: ASCII、ISO-8859-1、GB2312、GBK都是表示了字符集又表示了對應的字符編碼,但Unicode字符集是特例,它對應的字符編碼有:UTF-8、UTF-16、UTF-32)
查看電腦默認的字符編碼
1、打開控制臺(win+R),輸入cmd回車
2、右鍵菜單欄選擇屬性
3、當前代碼頁就是對應的字符集編碼



編碼和解碼的由來
計算機的世界中,它只能懂得0和1(即二進制),但是,我們交流的時候是通過字符進行交流,所以,如果想要計算機了解我們想表達的東西,以及我們想了解計算機想表達的東西,就需要在字符和0與1之間進行轉換,也就是: 編碼和解碼
編碼和解碼
就編碼和解碼而言,針對的是我們(即在計算機中闖蕩的人),這樣就不會混淆這兩個概念。
編碼: 將字符按照對應的編碼類型轉換成計算機能夠識別的0或者1(類似于生活中的:將中文翻譯成英文的翻譯官)
解碼: 將0和1根據對應的解碼類型轉換成我們能夠讀懂的字符(類似于生活中的: 將英文翻譯成中文的翻譯官)
常見的字符集
ASCII、GB2312、Unicode、GBK等
(一)ASCII字符集和ASCII編碼
ASCII字符集: 全稱《美國信息交換標準代碼》,主要用于顯示現代英語和其它西歐語言,主要包括:可顯示字符(英文字母、阿拉伯數值、標點符號)、以及控制字符(回車、換行、退格等特殊字符)。
ASCII編碼: 美國定制的交換標準,目的是將ASCII字符集包含的字符轉換成計算機能夠識別的二進制(0和1),它是最通用的信息交換標準,到目前為止總共定義了128個字符。
ASCII編碼缺點: 只能顯示26個基本拉丁字母、阿拉伯數目字和英式標點符號,因此只能用于顯示現代美國英語(而且在處理英語當中的外來詞如naïve、café、élite等等時,所有重音符號都不得不去掉,即使這樣做會違反拼寫規則),而且對其他的語言支持力度也不大,所以現在蘋果也使用Unicode替換ASCII。
(二)GBXXXX字符集
(1) GB2312字符集:
- 全稱:《信息交換用漢字編碼字符集》,剛開始ASCII字符集只包含了阿拉伯數字、字母和一些特殊符號,這個編碼只適用于美國和西方的一些國家,而不適用于使用漢字的國家,為了使用漢字的國家也能夠和計算機進行溝通,中國國家標準總局發布了標準號為:GB2312的編碼格式,它適用于漢字處理、漢字通信等系統之間的信息交換,除了中國大陸使用外,新加坡等地也采用此編碼。
- GB2312字符集共收錄了6763個簡體漢字,它的收錄包括了拉丁字母、日文平假名等在內的682個全角字符,GB2312編碼可以將GB2312字符集包含的字符轉換成計算機能夠識別的二進制0和1。
(2)GBK字符集
- 全稱:《漢字內碼擴展規范》,因為GB2312字符集編碼只支持簡體漢字和一些特殊符號,繁體字和一個特殊簡體字都沒有收錄其中,所以微軟針對GB2312做了拓展,在GBK字符集中收錄了繁體字,并最早在Window95簡體中文版使用。
- GBK拓展了GB2312字符集,共收錄了兩萬多個文字,GBK編碼可以將GBK字符集收錄的字符轉換成計算機能夠識別的二進制0和1。
(3)GB18030字符集
- 全稱: 國家標準GB 18030-2005《信息技術 中文編碼字符集》,因為GBK是由微軟首先制定的,并不屬于國家標準,所以國家為了兼容GBK字符集指定了GB18030字符集,它是中華人民共和國現時最新的內碼字集,除了兼容GBK字符集外,還支持GB 13000及Unicode字符集的全部統一漢字。
- GB 18030字符集共收錄漢字七萬多個,并且存儲方式采用的是可變長字節編碼,每個字可以由1個、2個或4個字節組成。
(二)Unicode字符集
- Unicode字符集的出現: 當計算機出現在全球各地時,為了與計算機進行交流,制定了各種各樣的標準如GB232/GBK/GB18030/BIG5的編碼方案,如果只在符合對應標準的地區使用則完全沒有問題,但是如果通過網絡與其他的地區進行交流時,因為各地的編碼的標準都不一樣,就會在轉換中出現"亂碼"現象,為了解決這個問題,Unicode字符集應運而生。
- Unicode也稱為: 統一碼/萬國碼/單一碼,它是業界的一種標準,通過它計算機可以實現世界上不同地區數十種文字的顯示,2005年Unicode就已經收錄了超過十萬個字符,現在由Unicode組織進行管理運作。
- Unicode編碼系統為表達任意語言的任意字符而設計,它為每種語言中的每個字符設定了統一并且唯一的二進制編碼,以滿足跨語言、跨平臺進行文本轉換、處理的要求。
- Unicode編碼標準現在有三種具體實現,分別是:UTF-8、UTF-16、UTF-32。
(1) UTF-8字符編碼:
- 它是實現了Unicode編碼方案的一種可變長字符編碼(定長碼),也是一種前綴碼。
- 它可以用來表示Unicode標準中的任何字符,且其編碼中的第一個字節仍與ASCII兼容,這使得原來處理ASCII字符的軟件無須或只須做少部份修改,即可繼續使用。
- UTF-8已經逐漸成為電子郵件、網頁及其他存儲或傳送文字的應用中,優先采用的編碼。
- 互聯網工程工作小組(IETF)要求所有互聯網協議都必須支持UTF-8編碼。
- UTF-8編碼使用一至四個字節為每個字符編碼(其中ASCII字符集中的128個字符只占1字節,還有附加符文的拉丁文、希臘文等需要2個字節,其他常用的文字占用3個字節,還有極少數的字符占用4個字節)。
(2) UTF-16字符編碼:
- 它是實現了Unicode編碼方案的一種可變長字符編碼(定長碼)
- 因為Unicode字符集中收錄了很多字符,但是常用的一般不會超過65535個以外的字符,所以出現了UTF-16(2字節=16位)。
- UTF-16優點: 它在空間效率上比UTF-32高兩倍,因為每個字符只需要2個字節來存儲(除去65535范圍以外的),而不是UTF-32中的4個字節。
- UTF-16缺點: 不兼容ASCII。
(3) UTF-32字符編碼:
- 它是實現了Unicode方案的一種定長字符編碼。
- 它使用4個字節的數字來表示每個字母、符號,或者表意文字(ideograph)。
- 優缺點: 使用4個字節存儲每個字符,效率高,處理速度快(因為不用計算需要幾個字節進行存儲),但是浪費空間。
四:舉例說明編碼與解碼的過程
通過上面的基礎規則學習,我們已經對字符集、編碼、解碼等基礎知識有了基本的認識。現在我們就通過圖形化來舉一個例子更加形象理解的這些知識(以:ASCII字符集為準,用我們編程入門的最常見的字符串:hello world為例子)
編碼: 在屏幕輸入文字 -> 根據指定編碼類型 -> 將輸入的文字編碼成計算機能夠識別的二進制數 -> 計算機存儲編輯成的二進制數值

解碼: 計算機讀取存儲的二進制數值 -> 根據指定的解碼類型解碼 -> 將二進制數值解碼成字符集中表達的字符 -> 在屏幕顯示

五:亂碼出現的原因
通過上面的例子,我們能夠更加清楚編碼和解碼的過程。同時,也看出了亂碼出現的原因:
- 編碼過程和解碼過程使用的編碼方式不一致
- 編碼/解碼對應的字符集不存在對應的字符
六:解決亂碼
知道出現亂碼的兩個原因,要解決亂碼就要同時滿足以下兩個條件:
1. 編碼過程和解碼過程使用同一種編碼方式
2. 使用支持需要編碼解碼的字符串對應的字符集

七:經常遇到的亂碼場景與解決
一:IDEA工具出現亂碼
File -> setting -> 輸入File encoding -> 設置成對應的字符集

二:MySQL數據庫亂碼和編碼設置
通過控制臺登錄到mysql后:
- 查詢當前默認的數據庫編碼方式:
show variables like 'character_set%'

- 設置數據庫編碼方式
//當前會話,退出控制臺后又恢復回原來默認的編碼方式
set character_set_server=utf8;
set character_set_database=utf8;
//全集范圍,無論是否退出控制臺,以后都是使用這個編碼方式
set global character_set_database=utf8;
set global character_set_server=utf8;
八:參考和感謝
1、w3c網站-字符集和字符編碼(Charset & Encoding)
2、亂碼的產生和解決
九:總結
相信看到這里,你對亂碼的會有了更深的認識,學習一個知識,只有知道這個知識的原理,才不會感覺一知半解。
感謝你閱讀本文,如果你覺得文章哪里存在錯誤,歡迎私信或者在下方留言指出。如果你覺得本文對你有一些幫助,可以給我一個點贊和關注,讓我有更多動力給大家帶來更多的文章,謝謝。
關注公眾號【是秘密呀joy】架構師視頻、技術文章、面試資料、IDEA工具免費分享,不定時抽獎,只等你來!