java 中文字符串,utf-8编码为byte数组的计算过程

本文详细介绍了Unicode转UTF-8的规则及计算过程,通过实例演示如何将汉字“中”编码为UTF-8格式,包括从Unicode到二进制再到字节数组的具体步骤。

背景:

 对于编码解码的计算过程一直没有去研究过。以前也看了大神写的编码解码的文章,当时看了似懂非懂,没有仔细去品味,没去实践。正应了那句老话:纸上得来终觉浅,绝知此事要躬行。

 为什么有编码和解码?二什么时候会出现编码和解码?编码解码的算法是怎样的?

         推荐两篇文章

 

                        http://www.ibm.com/developerworks/cn/java/j-lo-chinesecoding/

                         http://blog.youkuaiyun.com/baixiaoshi/article/details/40786503

          已经回答的很好了,^^偷懒不写了。

基础知识:

unicode转换为utf-8编码的规则

 

Unicode         UTF-8

 

0000-007F      0xxxxxxx

 

0080-07FF     110xxxxx 10xxxxxx

 

0800-FFFF    1110xxxx 10xxxxxx 10xxxxxx

 

 如果字符对应编码值小于0x7F,则转换该为1byte,最高位为00x7F转换为二进制为111111,71。不会出现最高位为1,最高位为1肯定大于7F。),该字符对应的二进制替换X,不足7位前面高位加0

 

    编码值在008007FF字符,会转换为2个字节,并且第一个字节以110开头,第二个字节以10开头,字符对应的编码值转换为2进制后的数据,填充X。不足位数的高位加0

 

    编码值在0800FFFF字符,会转换为3个字节,并且第一个字节以1110开头,后面字节以10开头,字符对应的编码值转换为2进制后的数据,填充X。不足位数的高位加0

 

    也就是说大于07XX编码值的字符,转换为字节时,第一个字节中连续1的个数表示该字符对应字节的长度

计算过程

          

String name = "中";
char[] chars = name.toCharArray();
//使用utf-8编码字符集
Charset charset = Charset.forName("utf-8");
CharBuffer charBuffer = CharBuffer.allocate(chars.length);
charBuffer.put(chars);
charBuffer.flip();
//字符编码为字节数组
ByteBuffer byteBuffer = charset.encode(charBuffer);
byte[] charToBytes = byteBuffer.array();
System.out.println("chars.length:" + chars.length+";bytes.length:" + charToBytes.length);
byte[] bytes = name.getBytes("utf-8");

 

 

    运行后byte数组值,可通过debug查看

 

 

   转换过程

“中”的unicode通过查unicode编码表可知为:4E2D(十六进制的数,附件是网上找的一个编码表),通过转换为二进制:100111000101101。4E2D落在了0800~ FFFF区间内,再依据前面转换规则填充x。

 

   填充过程:

最后获得 11100100  10111000 10101101

 

二进制到byte的换算过程

 

根据1个字节占8位,换算为字节数组[224,184,173],这和程序运行结果[-28-72-83],对不上,脑袋当时就卡了。然后一想不对呀,javabyte的范围是-128127,手工算出来的是224,184,173这明显超出了byte数值的范围。又一想这都是按无符号数进行二进制转换为byte。查了下无符号数转换为有符号数的规则(也有说这是补码):最高位用来表示符号,其余按位取反再加1

 

            按位取反                 1

11100100--------------->10011011-------------> 10011100

 

 最高位为符号位不参与计算,剩下的二进制0011100转换为十进制为 28,加上符号为-28

同理

        10111000转换后的十进制为 :-72

        10101101转换后的十进制为:-83

 

          最终和程序运行结果一样。

 

 

<think>我们正在处理用户的问题:如何将Java字符串使用UTF-8编码换为字节数组。 根据引用[2]和[3],我们知道Java字符串内部使用UTF-16编码存储。但是,我们可以使用getBytes(Charset)方法将其换为指定字符集的字节数组。 具体到用户需求:使用UTF-8编码字符串换为字节数组。 步骤: 1. 使用String类的getBytes方法,并指定字符集为UTF-8。 2. 字符集可以通过标准字符集名称"UTF-8"或者使用StandardCharsets类中定义的常量(在Java 7及以上)来指定。 示例代码: 方法一:使用字符串指定字符集名称 byte[] bytes = str.getBytes("UTF-8"); 方法二:使用StandardCharsets.UTF_8(推荐,避免拼写错误和异常处理) import java.nio.charset.StandardCharsets; ... byte[] bytes = str.getBytes(StandardCharsets.UTF_8); 注意:方法一需要处理UnsupportedEncodingException(但UTF-8Java平台必须支持的,所以实际上不会抛出,但编译器要求捕获或声明抛出)。方法二(使用StandardCharsets)不需要处理异常,更简洁。 因此,推荐使用StandardCharsets方式。 另外,引用[4]也提到:字符串对象在Java中已经是Unicode字符序列(UTF-16),所以换时只需指定目标编码即可。 下面给出完整示例:</think>在Java中,将字符串换为UTF-8编码的字节数组,需使用`getBytes()`方法并指定字符集。以下是详细步骤和示例: ### 解决方案 ```java import java.nio.charset.StandardCharsets; public class StringToUtf8 { public static void main(String[] args) { String text = "你好, World!"; // 示例字符串 // 方法1:使用StandardCharsets常量(推荐) byte[] utf8Bytes = text.getBytes(StandardCharsets.UTF_8); // 方法2:使用字符集名称 byte[] utf8Bytes2 = text.getBytes("UTF-8"); // 需处理UnsupportedEncodingException // 验证结果 System.out.println("UTF-8字节长度: " + utf8Bytes.length); System.out.println("字节内容: " + Arrays.toString(utf8Bytes)); } } ``` ### 关键说明 1. **字符集指定** - 使用`StandardCharsets.UTF_8`常量(Java 7+)是最安全的方式[^3][^4] - 直接传递字符串`"UTF-8"`需处理`UnsupportedEncodingException`(但UTF-8是所有Java平台必须支持的编码) 2. **内部换机制** Java字符串在内存中始终以UTF-16格式存储,`getBytes()`方法执行从UTF-16到指定编码(如UTF-8)的实时码[^3][^4] 3. **字节长度差异** UTF-8编码中: - ASCII字符(如英文)占1字节 - 常用汉字占3字节 示例中`"你好, World!"`的字节长度为: $$3 \times 2 + 7 \times 1 + 1 = 14 \text{ bytes}$$ (2个汉字×3字节 + 7个英文/符号×1字节 + 逗号1字节) ### 注意事项 - 避免使用无参数的`getBytes()`,它依赖平台默认编码(可能导致跨平台不一致)[^2] - 处理二进制数据时,需显式指定编码避免乱码[^4] - 换后的字节数组不可直接当作字符串处理,需用`new String(byte[], StandardCharsets.UTF_8)`解码 ### 相关问题 1. 如何将UTF-8字节数组重新解码字符串? 2. JavaUTF-8UTF-16编码的主要区别是什么? 3. 为什么处理文件I/O时需要显式指定字符编码? 4. 如何计算字符串在特定编码下的字节长度? [^1]: 字符串字节数组编码结果示例 [^2]: 无参数`getBytes()`使用平台默认编码的风险 [^3]: Java字符串内部始终以UTF-16存储 [^4]: 编码换需显式指定目标字符集
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值