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

13 篇文章 2 订阅
1 篇文章 0 订阅

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

}

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

  • 11
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值