前言:上一篇文章寫了關於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);
}
}
運行結果: