1. 程式人生 > >Java語言中一個字元佔幾個位元組?

Java語言中一個字元佔幾個位元組?

要區分清楚內碼(internal encoding)和外碼(external encoding)就好了。

內碼是程式內部使用的字元編碼,特別是某種語言實現其char或String型別在記憶體裡用的內部編碼;
外碼是程式與外部互動時外部使用的字元編碼。“外部”相對“內部”而言;不是char或String在記憶體裡用的內部編碼的地方都可以認為是“外部”。例如,外部可以是序列化之後的char或String,或者外部的檔案、命令列引數之類的。

Java語言規範規定,Java的char型別是UTF-16的code unit,也就是一定是16位(2位元組);

char, whose values are 16-bit unsigned integers representing UTF-16 code units (
§3.1
).

然後字串是UTF-16 code unit的序列:

The Java programming language represents text in sequences of 16-bit code units, using the UTF-16 encoding.

這樣,Java規定了字元的內碼要用UTF-16編碼。或者至少要讓使用者無法感知到String內部採用了非UTF-16的編碼。

 

另舉一例:
Java標準庫實現的對char與String的序列化規定使用UTF-8作為外碼。Java的Class檔案中的字串常量與符號名字也都規定用UTF-8編碼。這大概是當時設計者為了平衡執行時的時間效率(採用定長編碼的UTF-16)與外部儲存的空間效率(採用變長的UTF-8編碼)而做的取捨。
作者:國棟
連結:https://www.zhihu.com/question/27562173/answer/76208352
來源:知乎
著作權歸作者所有。商業轉載請聯絡作者獲得授權,非商業轉載請註明出處。
 

首先,你所謂的“字元”具體指什麼呢?

如果你說的“字元”就是指 Java 中的 char,那好,那它就是 16 位,2 位元組。

如果你說的“字元”是指我們用眼睛看到的那些“抽象的字元”,那麼,談論它佔幾個位元組是沒有意義的。

具體地講,脫離具體的編碼談某個字元佔幾個位元組是沒有意義的

就好比有一個抽象的整數“42”,你說它佔幾個位元組?這得具體看你是用 byte,short,int,還是 long 來存它。用 byte 存就佔一位元組,用 short 存就佔兩位元組,int 通常是四位元組,long 通常八位元組。當然,如果你用 byte,受限於它有限的位數,有些數它是存不了的,比如 256 就無法放在一個 byte 裡了。

字元是同樣的道理,如果你想談“佔幾個位元組”,就要先把編碼說清楚。

同一個字元在不同的編碼下可能佔不同的位元組

就以你舉的“ ”字為例,“ ”在 GBK 編碼下佔 2 位元組,在 UTF-16 編碼下也佔 2 位元組,在 UTF-8 編碼下佔 3 位元組,在 UTF-32 編碼下佔 4 位元組。

不同的字元在同一個編碼下也可能佔不同的位元組

”在 UTF-8 編碼下佔3位元組,而“ A”在 UTF-8 編碼下佔 1 位元組。(因為 UTF-8 是 變長編碼)

而 Java 中的 char 本質上是 UTF-16 編碼。而 UTF-16 實際上也是一個變長編碼(2 位元組或 4位元組)。

如果一個抽象的字元在 UTF-16 編碼下佔 4 位元組,顯然它是不能放到 char 中的。換言之, char 中只能放 UTF-16 編碼下只佔 2 位元組的那些字元。

而 getBytes 實際是做編碼轉換,你應該顯式傳入一個引數來指定編碼,否則它會使用預設編碼來轉換。

你說“ new String("字").getBytes().length 返回的是3 ”,這說明預設編碼是 UTF-8.如果你顯式地傳入一個引數,比如這樣“ new String("字").getBytes(" GBK").length ”,那麼返回就是 2.

你可以在啟動 JVM 時設定一個預設編碼,

假設你的類叫 Main,那麼在命令列中用 java 執行這個類時可以通過 file.encoding 引數設定一個預設編碼。比如這樣:java -D file.encoding= GBKMain這時,你再執行不帶引數的 getBytes() 方法時,new String("字").getBytes().length 返回的就是 2 了,因為現在預設編碼變成 GBK 了。當然,如果這時你顯式地指定編碼,new String("字").getBytes(" UTF-8").length 返回的則依舊是 3.

否則,會使用所在作業系統環境下的預設編碼。

通常,Windows 系統下是 GBK,Linux 和 Mac 是 UTF-8.但有一點要注意,在 Windows 下使用 IDE 來執行時,比如 Eclipse,如果你的工程的預設編碼是 UTF-8,在 IDE 中執行你的程式時,會加上上述的 -D file.encoding= UTF-8 引數,這時,即便你在 Windows 下,預設編碼也是 UTF-8,而不是 GBK。

由於受啟動引數及所在作業系統環境的影響,不帶引數的 getBytes 方法通常是不建議使用的,最好是顯式地指定引數以此獲得穩定的預期行為。