Java中的UTF-8、UTF-16編碼字元所佔位元組數
阿新 • • 發佈:2019-02-05
前言:上一篇文章寫了關於Unicode,以及utf-8、utf-16相關知識。所以本篇博文來驗證在java環境下,字元在不同編碼下所佔的字計數。
測試程式碼如下:
package string;
public class CharByteTest {
public static void main(String[] args) throws Exception {
// 第二個字元為BMP之外的字元,csdn編輯器無法顯示該字元,可以在執行結果截圖中看到
String[] strArr = {"中", "��", "a", "aa"};
String[] charsetArr = {"gbk" , "utf-8", "utf-16", "gb2312"};
for(String str : strArr) {
System.out.println(str);
for(String charset : charsetArr) {
byteTest(str, charset);
}
System.out.println("============================");
}
}
public static void byteTest(String str, String charset) throws Exception {
System.out.println("編碼:" + charset
+ "\t所佔位元組數:" + str.getBytes(charset).length);
}
}
執行結果如下:
在前一篇文章的基礎上,我們來分析一下執行結果。
- “中”字的unicode碼值為4E2D,使用UTF-8編碼佔3個位元組。由於該字元位於BMP內,所以使用UTF-16編碼應該佔2個位元組,但是執行結果為4個位元組。
- 第二個字元(csdn編輯器不支援該字元的顯示),該字元使用UTF-8應該佔4個位元組,執行結果正確。由於該字元位於BMP外,所以使用UTF-16編碼應該佔4個自己,但是執行結果顯示佔用了6個位元組。
- 英文字母a,UTF-8編碼應該和ASCII編碼相同佔用一個位元組,執行結果顯示佔用一個位元組。a在Unicode中位於BMP內,所以UTF-16編碼應該佔用4個位元組,但是執行結果缺顯示4個位元組。
- 按照上面的執行結果,a在UTF-8編碼下佔用1個位元組,在UTF-16編碼下佔用4個位元組。那麼猜測兩個英文字母a,即”aa“在UTF-8和UTF-16編碼下應該分別佔2個和8個位元組,但是執行結果卻和想象中的不一樣,aa在UTF-16編碼下工佔6個位元組。
執行結果好像和上一篇中講到的有點不相符啊!為什麼會出現這樣的結果的?
通過搜尋相關文章,瞭解到java的位元組碼檔案(.class)檔案採用的是UTF-8編碼,但是在java 執行時會使用UTF-16編碼。在轉碼的時候會在前面加上表示位元組順序的字元,這個字元稱為”零寬度非換行空格”(ZERO WIDTH NO-BREAK SPACE),用FEFF表示。FEFF佔用兩個位元組,所以就解釋了為什麼java環境下英文字母a在UTF-16編碼佔3個位元組。
我們不妨將這些字元的在不同編碼下的二進位制轉換為16進位制並打印出來。
將程式碼修改如下:
package string;
public class CharByteTest {
private static char[] HEX_CHAR = {'0', '1', '2', '3', '4',
'5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
public static void main(String[] args) throws Exception {
String[] strArr = {"中", "��", "a", "aa"};
//String[] charsetArr = {"gbk", "utf-8", "utf-16", "gb2312"};
String[] charsetArr = {"unicode", "utf-8", "utf-16", "utf-16BE", "utf-16LE"};
for(String str : strArr) {
System.out.println(str);
for(String charset : charsetArr) {
byteTest(str, charset);
}
System.out.println("============================");
}
}
public static void byteTest(String str, String charset) throws Exception {
byte[] strByte = str.getBytes(charset);
System.out.println("編碼:" + charset
+ "\t所佔位元組數:" + strByte.length
+ "\t16進位制:" + bytesToHexStr(strByte));
}
// 將byte[]用十六進位制字串
public static String bytesToHexStr(byte[] bytes) {
int index = 0;
char[] hexChar = new char[bytes.length * 2];
for(int i = 0; i < bytes.length; i++) {
hexChar[index++] = HEX_CHAR[bytes[i] >> 4 & 0xF];
hexChar[index++] = HEX_CHAR[bytes[i] & 0xF];
}
return new String(hexChar);
}
}
執行結果: