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,揭示了字符编码对字符串长度计算的影响。核心要点:

  1. 字符数 ≠ 字节数:非ASCII字符会导致两者差异
  2. 编码是关键:变长编码(如UTF-8)更高效但计算复杂
  3. 场景决定方法
    • 字符操作 → length()
    • 字节操作 → getBytes().length(务必指定编码)

完整示例代码见 GitHub仓库


原始标题:Java’s String.length() and String.getBytes().length | Baeldung