App下載

總結(jié)歸納Java基礎(chǔ)知識(shí)點(diǎn)之字符串編碼的詳細(xì)內(nèi)容

怪味少女 2021-08-17 14:53:20 瀏覽數(shù) (1859)
反饋

一、為什么要編碼

不知道大家有沒有想過一個(gè)問題,那就是為什么要編碼?我們能不能不編碼?要回答這個(gè)問題必須要回到計(jì)算機(jī)是如何表示我們?nèi)祟惸軌蚶斫獾姆?hào)的,這些符號(hào)也就是我們?nèi)祟愂褂玫恼Z言。由于人類的語言有太多,因而表示這些語言的符號(hào)太多,無法用計(jì)算機(jī)中一個(gè)基本的存儲(chǔ)單元—— byte 來表示,因而必須要經(jīng)過拆分或一些翻譯工作,才能讓計(jì)算機(jī)能理解。我們可以把計(jì)算機(jī)能夠理解的語言假定為英語,其它語言要能夠在計(jì)算機(jī)中使用必須經(jīng)過一次翻譯,把它翻譯成英語。這個(gè)翻譯的過程就是編碼。所以可以想象只要不是說英語的國家要能夠使用計(jì)算機(jī)就必須要經(jīng)過編碼。這看起來有些霸道,但是這就是現(xiàn)狀,這也和我們國家現(xiàn)在在大力推廣漢語一樣,希望其它國家都會(huì)說漢語,以后其它的語言都翻譯成漢語,我們可以把計(jì)算機(jī)中存儲(chǔ)信息的最小單位改成漢字,這樣我們就不存在編碼問題了。

所以總的來說,編碼的原因可以總結(jié)為:

  • 計(jì)算機(jī)中存儲(chǔ)信息的最小單元是一個(gè)字節(jié)即 8 個(gè) bit,所以能表示的字符范圍是 0~255 個(gè)
  • 人類要表示的符號(hào)太多,無法用一個(gè)字節(jié)來完全表示,要解決這個(gè)矛盾必須需要一個(gè)新的數(shù)據(jù)結(jié)構(gòu) char,從 char 到 byte 必須編碼

二、如何“翻譯”

明白了各種語言需要交流,經(jīng)過翻譯是必要的,那又如何來翻譯呢?計(jì)算中提拱了多種翻譯方式,常見的有 ASCII、ISO-8859-1、GB2312、GBK、UTF-8、UTF-16 等。它們都可以被看作為字典,它們規(guī)定了轉(zhuǎn)化的規(guī)則,按照這個(gè)規(guī)則就可以讓計(jì)算機(jī)正確的表示我們的字符。目前的編碼格式很多,例如 GB2312、GBK、UTF-8、UTF-16 這幾種格式都可以表示一個(gè)漢字,那我們到底選擇哪種編碼格式來存儲(chǔ)漢字呢?這就要考慮到其它因素了,是存儲(chǔ)空間重要還是編碼的效率重要。根據(jù)這些因素來正確選擇編碼格式,下面簡(jiǎn)要介紹一下這幾種編碼格式。

  • ASCII 碼

學(xué)過計(jì)算機(jī)的人都知道 ASCII 碼,總共有 128 個(gè)(0-127),用一個(gè)字節(jié)的低 7 位表示,0~31 是控制字符如換行回車刪除等;32~126 是打印字符,可以通過鍵盤輸入并且能夠顯示出來。

其中48~57為0到9十個(gè)阿拉伯?dāng)?shù)字
65~90為26個(gè)大寫英文字母
97~122號(hào)為26個(gè)小寫英文字母

  • ISO-8859-1

128 個(gè)字符顯然是不夠用的,于是 ISO 組織在 ASCII 碼基礎(chǔ)上又制定了一些列標(biāo)準(zhǔn)用來擴(kuò)展 ASCII 編碼,它們是 ISO-8859-1~ISO-8859-15,其中 ISO-8859-1 涵蓋了大多數(shù)西歐語言字符,所有應(yīng)用的最廣泛。ISO-8859-1 仍然是單字節(jié)編碼,它總共能表示 256 個(gè)字符。

  • GB2312

它的全稱是《信息交換用漢字編碼字符集 基本集》,它是雙字節(jié)編碼,總的編碼范圍是 A1-F7,其中從 A1-A9 是符號(hào)區(qū),總共包含 682 個(gè)符號(hào),從 B0-F7 是漢字區(qū),包含 6763 個(gè)漢字。

  • GBK

全稱叫《漢字內(nèi)碼擴(kuò)展規(guī)范》,是國家技術(shù)監(jiān)督局為 windows95 所制定的新的漢字內(nèi)碼規(guī)范,它的出現(xiàn)是為了擴(kuò)展 GB2312,加入更多的漢字,它的編碼范圍是 8140~FEFE(去掉 XX7F)總共有 23940 個(gè)碼位,它能表示 21003 個(gè)漢字,它的編碼是和 GB2312 兼容的,也就是說用 GB2312 編碼的漢字可以用 GBK 來解碼,并且不會(huì)有亂碼。

  • GB18030

全稱是《信息交換用漢字編碼字符集》,是我國的強(qiáng)制標(biāo)準(zhǔn),它可能是單字節(jié)、雙字節(jié)或者四字節(jié)編碼,它的編碼與 GB2312 編碼兼容,這個(gè)雖然是國家標(biāo)準(zhǔn),但是實(shí)際應(yīng)用系統(tǒng)中使用的并不廣泛。

  • UTF-16

說到 UTF 必須要提到 Unicode(Universal Code 統(tǒng)一碼),ISO 試圖想創(chuàng)建一個(gè)全新的超語言字典,世界上所有的語言都可以通過這本字典來相互翻譯??上攵@個(gè)字典是多么的復(fù)雜,關(guān)于 Unicode 的詳細(xì)規(guī)范可以參考相應(yīng)文檔。Unicode 是 Java 和 XML 的基礎(chǔ),下面詳細(xì)介紹 Unicode 在計(jì)算機(jī)中的存儲(chǔ)形式。

UTF-16 具體定義了 Unicode 字符在計(jì)算機(jī)中存取方法。UTF-16 用兩個(gè)字節(jié)來表示 Unicode 轉(zhuǎn)化格式,這個(gè)是定長(zhǎng)的表示方法,不論什么字符都可以用兩個(gè)字節(jié)表示,兩個(gè)字節(jié)是 16 個(gè) bit,所以叫 UTF-16。UTF-16 表示字符非常方便,每?jī)蓚€(gè)字節(jié)表示一個(gè)字符,這個(gè)在字符串操作時(shí)就大大簡(jiǎn)化了操作,這也是 Java 以 UTF-16 作為內(nèi)存的字符存儲(chǔ)格式的一個(gè)很重要的原因。

  • UTF-8

UTF-16 統(tǒng)一采用兩個(gè)字節(jié)表示一個(gè)字符,雖然在表示上非常簡(jiǎn)單方便,但是也有其缺點(diǎn),有很大一部分字符用一個(gè)字節(jié)就可以表示的現(xiàn)在要兩個(gè)字節(jié)表示,存儲(chǔ)空間放大了一倍,在現(xiàn)在的網(wǎng)絡(luò)帶寬還非常有限的今天,這樣會(huì)增大網(wǎng)絡(luò)傳輸?shù)牧髁?,而且也沒必要。而 UTF-8 采用了一種變長(zhǎng)技術(shù),每個(gè)編碼區(qū)域有不同的字碼長(zhǎng)度。不同類型的字符可以是由 1~6 個(gè)字節(jié)組成。
UTF-8 有以下編碼規(guī)則:

1、如果一個(gè)字節(jié),最高位(第 8 位)為 0,表示這是一個(gè) ASCII 字符(00 - 7F)??梢姡?ASCII 編碼已經(jīng)是 UTF-8 了。
2、如果一個(gè)字節(jié),以 11 開頭,連續(xù)的 1 的個(gè)數(shù)暗示這個(gè)字符的字節(jié)數(shù),例如:110xxxxx 代表它是雙字節(jié) UTF-8 字符的首字節(jié)。
3、如果一個(gè)字節(jié),以 10 開始,表示它不是首字節(jié),需要向前查找才能得到當(dāng)前字符的首字節(jié)

三、Java 中需要編碼的場(chǎng)景

前面描述了常見的幾種編碼格式,下面將介紹 Java 中如何處理對(duì)編碼的支持,什么場(chǎng)合中需要編碼。

3.1 I/O 操作中存在的編碼

我們知道涉及到編碼的地方一般都在字符到字節(jié)或者字節(jié)到字符的轉(zhuǎn)換上,而需要這種轉(zhuǎn)換的場(chǎng)景主要是在 I/O 的時(shí)候,這個(gè) I/O 包括磁盤 I/O 和網(wǎng)絡(luò) I/O,關(guān)于網(wǎng)絡(luò) I/O 部分在后面將主要以 Web 應(yīng)用為例介紹。下圖是 Java 中處理 I/O 問題的接口:

這里寫圖片描述

Reader 類是 Java 的 I/O 中讀字符的父類,而 InputStream 類是讀字節(jié)的父類,InputStreamReader 類就是關(guān)聯(lián)字節(jié)到字符的橋梁,它負(fù)責(zé)在 I/O 過程中處理讀取字節(jié)到字符的轉(zhuǎn)換,而具體字節(jié)到字符的解碼實(shí)現(xiàn)它由 StreamDecoder 去實(shí)現(xiàn),在 StreamDecoder 解碼過程中必須由用戶指定 Charset 編碼格式。值得注意的是如果你沒有指定 Charset,將使用本地環(huán)境中的默認(rèn)字符集,例如在中文環(huán)境中將使用 GBK 編碼。

寫的情況也是類似,字符的父類是 Writer,字節(jié)的父類是 OutputStream,通過 OutputStreamWriter 轉(zhuǎn)換字符到字節(jié)。如下圖所示:

這里寫圖片描述

同樣 StreamEncoder 類負(fù)責(zé)將字符編碼成字節(jié),編碼格式和默認(rèn)編碼規(guī)則與解碼是一致的。

如下面一段代碼,實(shí)現(xiàn)了文件的讀寫功能:

String file = "c:/stream.txt"; 
String charset = "UTF-8"; 
// 寫字符換轉(zhuǎn)成字節(jié)流
FileOutputStream outputStream = new FileOutputStream(file); 
OutputStreamWriter writer = new OutputStreamWriter( 
outputStream, charset); 
try { 
   writer.write("這是要保存的中文字符"); 
} finally { 
   writer.close(); 
} 
// 讀取字節(jié)轉(zhuǎn)換成字符
FileInputStream inputStream = new FileInputStream(file); 
InputStreamReader reader = new InputStreamReader( 
inputStream, charset); 
StringBuffer buffer = new StringBuffer(); 
char[] buf = new char[64]; 
int count = 0; 
try { 
   while ((count = reader.read(buf)) != -1) { 
       buffer.append(buffer, 0, count); 
   } 
} finally { 
   reader.close(); 
}

在我們的應(yīng)用程序中涉及到 I/O 操作時(shí)只要注意指定統(tǒng)一的編解碼 Charset 字符集,一般不會(huì)出現(xiàn)亂碼問題,有些應(yīng)用程序如果不注意指定字符編碼,中文環(huán)境中取操作系統(tǒng)默認(rèn)編碼,如果編解碼都在中文環(huán)境中,通常也沒問題,但是還是強(qiáng)烈的不建議使用操作系統(tǒng)的默認(rèn)編碼,因?yàn)檫@樣,你的應(yīng)用程序的編碼格式就和運(yùn)行環(huán)境綁定起來了,在跨環(huán)境下很可能出現(xiàn)亂碼問題。

3.2 內(nèi)存中操作中的編碼

在 Java 開發(fā)中除了 I/O 涉及到編碼外,最常用的應(yīng)該就是在內(nèi)存中進(jìn)行字符到字節(jié)的數(shù)據(jù)類型的轉(zhuǎn)換,Java 中用 String 表示字符串,所以 String 類就提供轉(zhuǎn)換到字節(jié)的方法,也支持將字節(jié)轉(zhuǎn)換為字符串的構(gòu)造函數(shù)。如下代碼示例:

String s = "這是一段中文字符串"; 
byte[] b = s.getBytes("UTF-8"); 
String n = new String(b,"UTF-8");

另外一個(gè)是已經(jīng)被被廢棄的 ByteToCharConverter 和 CharToByteConverter 類,它們分別提供了 convertAll 方法可以實(shí)現(xiàn) byte[] 和 char[] 的互轉(zhuǎn)。如下代碼所示:

ByteToCharConverter charConverter = ByteToCharConverter.getConverter("UTF-8"); 
char c[] = charConverter.convertAll(byteArray); 
CharToByteConverter byteConverter = CharToByteConverter.getConverter("UTF-8"); 
byte[] b = byteConverter.convertAll(c);

這兩個(gè)類已經(jīng)被 Charset 類取代,Charset 提供 encode 與 decode 分別對(duì)應(yīng) char[] 到 byte[] 的編碼和 byte[] 到 char[] 的解碼。如下代碼所示:

Charset charset = Charset.forName("UTF-8"); 
ByteBuffer byteBuffer = charset.encode(string); 
CharBuffer charBuffer = charset.decode(byteBuffer);

編碼與解碼都在一個(gè)類中完成,通過 forName 設(shè)置編解碼字符集,這樣更容易統(tǒng)一編碼格式,比 ByteToCharConverter 和 CharToByteConverter 類更方便。

Java 中還有一個(gè) ByteBuffer 類,它提供一種 char 和 byte 之間的軟轉(zhuǎn)換,它們之間轉(zhuǎn)換不需要編碼與解碼,只是把一個(gè) 16bit 的 char 格式,拆分成為 2 個(gè) 8bit 的 byte 表示,它們的實(shí)際值并沒有被修改,僅僅是數(shù)據(jù)的類型做了轉(zhuǎn)換。如下代碼所以:

ByteBuffer heapByteBuffer = ByteBuffer.allocate(1024); 
ByteBuffer byteBuffer = heapByteBuffer.putChar(c);

以上這些提供字符和字節(jié)之間的相互轉(zhuǎn)換只要我們?cè)O(shè)置編解碼格式統(tǒng)一一般都不會(huì)出現(xiàn)問題。

四、Java 中如何編解碼

前面介紹了幾種常見的編碼格式,這里將以實(shí)際例子介紹 Java 中如何實(shí)現(xiàn)編碼及解碼,下面我們以“I am 君山”這個(gè)字符串為例介紹 Java 中如何把它以 ISO-8859-1、GB2312、GBK、UTF-16、UTF-8 編碼格式進(jìn)行編碼的。

public static void encode() { 
       String name = "I am 君山"; 
       toHex(name.toCharArray()); 
       try { 
           byte[] iso8859 = name.getBytes("ISO-8859-1"); 
           toHex(iso8859); 
           byte[] gb2312 = name.getBytes("GB2312"); 
           toHex(gb2312); 
           byte[] gbk = name.getBytes("GBK"); 
           toHex(gbk); 
           byte[] utf16 = name.getBytes("UTF-16"); 
           toHex(utf16); 
           byte[] utf8 = name.getBytes("UTF-8"); 
           toHex(utf8); 
       } catch (UnsupportedEncodingException e) { 
           e.printStackTrace(); 
       } 
}

我們把 name 字符串按照前面說的幾種編碼格式進(jìn)行編碼轉(zhuǎn)化成 byte 數(shù)組,然后以 16 進(jìn)制輸出,我們先看一下 Java 是如何進(jìn)行編碼的。

下面是 Java 中編碼需要用到的類圖

這里寫圖片描述

首先根據(jù)指定的 charsetName 通過 Charset.forName(charsetName) 設(shè)置 Charset 類,然后根據(jù) Charset 創(chuàng)建 CharsetEncoder 對(duì)象,再調(diào)用 CharsetEncoder.encode 對(duì)字符串進(jìn)行編碼,不同的編碼類型都會(huì)對(duì)應(yīng)到一個(gè)類中,實(shí)際的編碼過程是在這些類中完成的。

如字符串“I am 君山”的 char 數(shù)組為 49 20 61 6d 20 541b 5c71,下面把它按照不同的編碼格式轉(zhuǎn)化成相應(yīng)的字節(jié)。

4.1 按照 ISO-8859-1 編碼

字符串“I am 君山”用 ISO-8859-1 編碼,下面是編碼結(jié)果:

這里寫圖片描述

從上圖看出 7 個(gè) char 字符經(jīng)過 ISO-8859-1 編碼轉(zhuǎn)變成 7 個(gè) byte 數(shù)組,ISO-8859-1 是單字節(jié)編碼,中文“君山”被轉(zhuǎn)化成值是 3f 的 byte。3f 也就是“?”字符,所以經(jīng)常會(huì)出現(xiàn)中文變成“?”很可能就是錯(cuò)誤的使用了 ISO-8859-1 這個(gè)編碼導(dǎo)致的。中文字符經(jīng)過 ISO-8859-1 編碼會(huì)丟失信息,通常我們稱之為“黑洞”,它會(huì)把不認(rèn)識(shí)的字符吸收掉。由于現(xiàn)在大部分基礎(chǔ)的 Java 框架或系統(tǒng)默認(rèn)的字符集編碼都是 ISO-8859-1,所以很容易出現(xiàn)亂碼問題,后面將會(huì)分析不同的亂碼形式是怎么出現(xiàn)的。

4.2 按照 GB2312 編碼

字符串“I am 君山”用 GB2312 編碼,下面是編碼結(jié)果:

這里寫圖片描述

GB2312 對(duì)應(yīng)的 Charset 是 sun.nio.cs.ext. EUC_CN 而對(duì)應(yīng)的 CharsetDecoder 編碼類是 sun.nio.cs.ext. DoubleByte,

GB2312 字符集有一個(gè) char 到 byte 的碼表,不同的字符編碼就是查這個(gè)碼表找到與每個(gè)字符的對(duì)應(yīng)的字節(jié),然后拼裝成 byte 數(shù)組。查表的規(guī)則如下:

c2b[c2bIndex[char >> 8] + (char & 0xff)]

如果查到的碼位值大于 oxff 則是雙字節(jié),否則是單字節(jié)。雙字節(jié)高 8 位作為第一個(gè)字節(jié),低 8 位作為第二個(gè)字節(jié),如下代碼所示:

if (bb > 0xff) {    // DoubleByte 
           if (dl - dp < 2) 
               return CoderResult.OVERFLOW; 
           da[dp++] = (byte) (bb >> 8); 
           da[dp++] = (byte) bb; 
} else {                      // SingleByte 
           if (dl - dp < 1) 
               return CoderResult.OVERFLOW; 
           da[dp++] = (byte) bb; 
}

從上圖可以看出前 5 個(gè)字符經(jīng)過編碼后仍然是 5 個(gè)字節(jié),而漢字被編碼成雙字節(jié),在第一節(jié)中介紹到 GB2312 只支持 6763 個(gè)漢字,所以并不是所有漢字都能夠用 GB2312 編碼。

4.3 按照 GBK 編碼

字符串“I am 君山”用 GBK 編碼,下面是編碼結(jié)果:

這里寫圖片描述

你可能已經(jīng)發(fā)現(xiàn)上圖與 GB2312 編碼的結(jié)果是一樣的,沒錯(cuò) GBK 與 GB2312 編碼結(jié)果是一樣的,由此可以得出 GBK 編碼是兼容 GB2312 編碼的,它們的編碼算法也是一樣的。不同的是它們的碼表長(zhǎng)度不一樣,GBK 包含的漢字字符更多。所以只要是經(jīng)過 GB2312 編碼的漢字都可以用 GBK 進(jìn)行解碼,反過來則不然。

4.4 按照 UTF-16 編碼

字符串“I am 君山”用 UTF-16 編碼,下面是編碼結(jié)果:

這里寫圖片描述

用 UTF-16 編碼將 char 數(shù)組放大了一倍,單字節(jié)范圍內(nèi)的字符,在高位補(bǔ) 0 變成兩個(gè)字節(jié),中文字符也變成兩個(gè)字節(jié)。從 UTF-16 編碼規(guī)則來看,僅僅將字符的高位和地位進(jìn)行拆分變成兩個(gè)字節(jié)。特點(diǎn)是編碼效率非常高,規(guī)則很簡(jiǎn)單,由于不同處理器對(duì) 2 字節(jié)處理方式不同,Big-endian(高位字節(jié)在前,低位字節(jié)在后)或 Little-endian(低位字節(jié)在前,高位字節(jié)在后)編碼,所以在對(duì)一串字符串進(jìn)行編碼是需要指明到底是 Big-endian 還是 Little-endian,所以前面有兩個(gè)字節(jié)用來保存 BYTE_ORDER_MARK 值,UTF-16 是用定長(zhǎng) 16 位(2 字節(jié))來表示的 UCS-2 或 Unicode 轉(zhuǎn)換格式,通過代理對(duì)來訪問 BMP 之外的字符編碼。

4.5 按照 UTF-8 編碼

字符串“I am 君山”用 UTF-8 編碼,下面是編碼結(jié)果:

這里寫圖片描述

UTF-16 雖然編碼效率很高,但是對(duì)單字節(jié)范圍內(nèi)字符也放大了一倍,這無形也浪費(fèi)了存儲(chǔ)空間,另外 UTF-16 采用順序編碼,不能對(duì)單個(gè)字符的編碼值進(jìn)行校驗(yàn),如果中間的一個(gè)字符碼值損壞,后面的所有碼值都將受影響。而 UTF-8 這些問題都不存在,UTF-8 對(duì)單字節(jié)范圍內(nèi)字符仍然用一個(gè)字節(jié)表示,對(duì)漢字采用三個(gè)字節(jié)表示。它的編碼規(guī)則如下:

private CoderResult encodeArrayLoop(CharBuffer src, 
ByteBuffer dst){ 
           char[] sa = src.array(); 
           int sp = src.arrayOffset() + src.position(); 
           int sl = src.arrayOffset() + src.limit(); 
           byte[] da = dst.array(); 
           int dp = dst.arrayOffset() + dst.position(); 
           int dl = dst.arrayOffset() + dst.limit(); 
           int dlASCII = dp + Math.min(sl - sp, dl - dp); 
           // ASCII only loop 
           while (dp < dlASCII && sa[sp] < 'u0080') 
               da[dp++] = (byte) sa[sp++]; 
           while (sp < sl) { 
               char c = sa[sp]; 
               if (c < 0x80) { 
                   // Have at most seven bits 
                   if (dp >= dl) 
                       return overflow(src, sp, dst, dp); 
                   da[dp++] = (byte)c; 
               } else if (c < 0x800) { 
                   // 2 bytes, 11 bits 
                   if (dl - dp < 2) 
                       return overflow(src, sp, dst, dp); 
                   da[dp++] = (byte)(0xc0 | (c >> 6)); 
                   da[dp++] = (byte)(0x80 | (c & 0x3f)); 
               } else if (Character.isSurrogate(c)) { 
                   // Have a surrogate pair 
                   if (sgp == null) 
                       sgp = new Surrogate.Parser(); 
                   int uc = sgp.parse(c, sa, sp, sl); 
                   if (uc < 0) { 
                       updatePositions(src, sp, dst, dp); 
                       return sgp.error(); 
                   } 
                   if (dl - dp < 4) 
                       return overflow(src, sp, dst, dp); 
                   da[dp++] = (byte)(0xf0 | ((uc >> 18))); 
                   da[dp++] = (byte)(0x80 | ((uc >> 12) & 0x3f)); 
                   da[dp++] = (byte)(0x80 | ((uc >>  6) & 0x3f)); 
                   da[dp++] = (byte)(0x80 | (uc & 0x3f)); 
                   sp++;  // 2 chars 
               } else { 
                   // 3 bytes, 16 bits 
                   if (dl - dp < 3) 
                       return overflow(src, sp, dst, dp); 
                   da[dp++] = (byte)(0xe0 | ((c >> 12))); 
                   da[dp++] = (byte)(0x80 | ((c >>  6) & 0x3f)); 
                   da[dp++] = (byte)(0x80 | (c & 0x3f)); 
               } 
               sp++; 
           } 
           updatePositions(src, sp, dst, dp); 
           return CoderResult.UNDERFLOW; 

UTF-8 編碼與 GBK 和 GB2312 不同,不用查碼表,所以在編碼效率上 UTF-8 的效率會(huì)更好,所以在存儲(chǔ)中文字符時(shí) UTF-8 編碼比較理想。

五、幾種編碼格式的比較

對(duì)中文字符后面四種編碼格式都能處理,GB2312 與 GBK 編碼規(guī)則類似,但是 GBK 范圍更大,它能處理所有漢字字符,所以 GB2312 與 GBK 比較應(yīng)該選擇 GBK。UTF-16 與 UTF-8 都是處理 Unicode 編碼,它們的編碼規(guī)則不太相同,相對(duì)來說 UTF-16 編碼效率最高,字符到字節(jié)相互轉(zhuǎn)換更簡(jiǎn)單,進(jìn)行字符串操作也更好。它適合在本地磁盤和內(nèi)存之間使用,可以進(jìn)行字符和字節(jié)之間快速切換,如 Java 的內(nèi)存編碼就是采用 UTF-16 編碼。但是它不適合在網(wǎng)絡(luò)之間傳輸,因?yàn)榫W(wǎng)絡(luò)傳輸容易損壞字節(jié)流,一旦字節(jié)流損壞將很難恢復(fù),想比較而言 UTF-8 更適合網(wǎng)絡(luò)傳輸,對(duì) ASCII 字符采用單字節(jié)存儲(chǔ),另外單個(gè)字符損壞也不會(huì)影響后面其它字符,在編碼效率上介于 GBK 和 UTF-16 之間,所以 UTF-8 在編碼效率上和編碼安全性上做了平衡,是理想的中文編碼方式。

到此這篇關(guān)于java基礎(chǔ)之字符串編碼知識(shí)點(diǎn)總結(jié)的文章就介紹到這了,更多相關(guān)java字符串編碼內(nèi)容,請(qǐng)搜索W3Cschool以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持!

0 人點(diǎn)贊