Java中的UTF-8、UTF-16编码字符所占字节数

来源:互联网 发布:uiautomator java 编辑:程序博客网 时间:2024/05/29 10:54

前言:上一篇文章写了关于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);    }}

运行结果如下:

这里写图片描述

在前一篇文章的基础上,我们来分析一下运行结果。

  1. “中”字的unicode码值为4E2D,使用UTF-8编码占3个字节。由于该字符位于BMP内,所以使用UTF-16编码应该占2个字节,但是运行结果为4个字节。
  2. 第二个字符(csdn编辑器不支持该字符的显示),该字符使用UTF-8应该占4个字节,运行结果正确。由于该字符位于BMP外,所以使用UTF-16编码应该占4个自己,但是运行结果显示占用了6个字节。
  3. 英文字母a,UTF-8编码应该和ASCII编码相同占用一个字节,运行结果显示占用一个字节。a在Unicode中位于BMP内,所以UTF-16编码应该占用4个字节,但是运行结果缺显示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);    }}

运行结果:
这里写图片描述

2 0
原创粉丝点击