1. 概述
在Java开发中,字符串操作是基础技能。理解字符串相关方法对编写高效、无bug的代码至关重要。
两个常用方法String.length()
和String.getBytes().length
看似相似,实则用途不同。本文将深入解析它们的区别,并探讨使用场景。
2. 初识String.length()
与String.getBytes().length
顾名思义:
- ✅
String.length()
:返回字符串的字符数量 - ✅
String.getBytes().length
:返回字符串按默认编码转换后的字节数组长度
对于纯ASCII字符串,两者结果可能相同:
String s = "beautiful";
assertEquals(9, s.length());
assertEquals(9, s.getBytes().length);
但这是否意味着它们永远相等?接着往下看。
3. 两者结果可能不同
JVM的默认字符编码(Charset)直接影响String.getBytes().length
的结果。不指定编码时,getBytes()
使用JVM默认编码方案。
可通过以下方式查看默认编码:
System.out.println(Charset.defaultCharset().displayName());
//输出: UTF-8
测试非ASCII字符串时,差异立现:
String de = "schöne"; // 德语
assertEquals(6, de.length()); // 6个字符
assertEquals(7, de.getBytes().length); // 7个字节
String cn = "美丽"; // 中文
assertEquals(2, cn.length()); // 2个字符
assertEquals(6, cn.getBytes().length); // 6个字节
为什么会出现这种差异?关键在于字符编码机制。
4. 字符编码机制
在分析差异原因前,先快速理解两种编码类型:
4.1. 定长编码
所有字符占用相同字节数。典型代表是UTF-32,固定使用4字节编码任何字符:
char byte1 byte2 byte3 byte4
b 0 0 0 98
e 0 0 0 101
...
使用UTF-32时,字节数始终是字符数的4倍:
Charset UTF_32 = Charset.forName("UTF_32");
String en = "beautiful";
assertEquals(9, en.length());
assertEquals(9 * 4, en.getBytes(UTF_32).length); // 36字节
String cn = "美丽";
assertEquals(2, cn.length());
assertEquals(2 * 4, cn.getBytes(UTF_32).length); // 8字节
⚠️ 缺点:ASCII字符只需1字节,但UTF-32仍占用4字节(3字节补零),空间浪费严重。
4.2. 变长编码
不同字符占用不同字节数。UTF-8(默认编码)就是典型代表,根据字符的码点(Code Point)使用1-4字节:
码点范围 | 字节数 |
---|---|
U+0000-U+007F | 1 |
U+0080-U+07FF | 2 |
U+0800-U+FFFF | 3 |
U+10000-U+10FFFF | 4 |
关键特性:
- ASCII字符(U+0000-U+007F)仅占1字节
- 非ASCII字符占用更多字节
验证字符码点:
assertEquals("f6", Integer.toHexString('ö')); // U+00F6 -> 2字节
assertEquals("7f8e", Integer.toHexString('美')); // U+7F8E -> 3字节
assertEquals("4e3d", Integer.toHexString('丽')); // U+4E3D -> 3字节
这就是为什么:
"schöne"
:5个ASCII字符(5字节)+ö
(2字节)= 7字节"美丽"
:美
(3字节)+丽
(3字节)= 6字节
5. 如何选择使用场景
根据操作类型选择合适方法:
✅ 使用String.length()
的场景
- 处理字符级逻辑时
- 需要获取字符数量时
- 典型案例:
- 用户输入长度验证
- 字符串位移操作(如字符轮转)
✅ 使用String.getBytes().length
的场景
- 处理字节级操作时
- 需要获取字节大小时
- 典型案例:
- 文件读写
- 网络传输
- 数据库存储
⚠️ 重要提醒:
getBytes()
默认使用JVM编码,可能因环境不同产生意外结果- 建议显式指定编码:
// 推荐写法 byte[] bytes = "美丽".getBytes(StandardCharsets.UTF_8); // 或 byte[] bytes = "美丽".getBytes(Charset.forName("UTF_16"));
6. 总结
本文通过对比String.length()
和String.getBytes().length
,揭示了字符编码对字符串长度计算的影响。核心要点:
- 字符数 ≠ 字节数:非ASCII字符会导致两者差异
- 编码是关键:变长编码(如UTF-8)更高效但计算复杂
- 场景决定方法:
- 字符操作 →
length()
- 字节操作 →
getBytes().length
(务必指定编码)
- 字符操作 →
完整示例代码见 GitHub仓库