length() 方法 - 获取字符数量(char 数量)
这是最常用、最基础的方法,它返回的是 String 对象内部表示的 char 数组的长度。

定义
public int length()
作用
返回 String 对象中的 16-bit char 数量。
示例
String str1 = "Hello"; System.out.println(str1.length()); // 输出 5 String str2 = "你好,世界"; System.out.println(str2.length()); // 输出 6 (每个中文字符在Java中通常占一个char)
重要提醒: 在 Java 中,char 类型是一个 16-bit 的无符号 Unicode 字符,这意味着 length() 方法返回的是 char 的数量,而不是用户感知的“字符”数量。
codePointCount() 方法 - 获取真正的字符数量(Grapheme Cluster)
现代 Unicode 字符集非常复杂,一个用户看到的“字符”(称为 Grapheme Cluster)可能由一个或多个 char 组成。length() 方法在这种情况下会给出错误的结果。
codePointCount() 方法就是为了解决这个问题而生的。

定义
public int codePointCount(int beginIndex, int endIndex)
作用
返回从 beginIndex 到 endIndex - 1 范围内,Unicode 代码点的数量,一个代码点可能对应一个 char,也可能对应一对 char(称为 代理对 Surrogate Pair)。
代理对
当 Unicode 字码超出 char 的表示范围(即大于 0xFFFF)时,Java 使用两个 char 来表示它,这被称为代理对,常见的例子包括:
- Emoji 表情符号 (😂, 👨👩👧👦)
- 某些特殊字符或字母 (如 𝄞, 𝒻)
示例
// 示例 1: Emoji 笑脸
String emoji = "😂";
System.out.println("length() 返回: " + emoji.length()); // 输出 2 (这是一个代理对)
System.out.println("codePointCount() 返回: " + emoji.codePointCount(0, emoji.length())); // 输出 1 (这才是用户感知的字符数量)
// 示例 2: 复合家庭 Emoji
String familyEmoji = "👨👩👧👦"; // 一个字符,由多个代码点组成
System.out.println("length() 返回: " + familyEmoji.length()); // 输出 11
System.out.println("codePointCount() 返回: " + familyEmoji.codePointCount(0, familyEmoji.length())); // 输出 1
// 示例 3: 普通字符串
String normal = "Java";
System.out.println("length() 返回: " + normal.length()); // 输出 4
System.out.println("codePointCount() 返回: " + normal.codePointCount(0, normal.length())); // 输出 4
如果你的应用需要处理国际化文本、Emoji 或任何可能包含代理对的字符,并且你需要计算用户能看到的“字符”数量,codePointCount() 是正确且可靠的选择。
charAt() 与 codePointAt() - 获取字符
与长度相对应,获取字符也有两个方法。
charAt(int index)
返回指定索引处的 char 值,如果该索引是一个代理对的第二个 char,它只会返回那个孤立的 char,这通常不是你想要的结果。
String emoji = "😂"; char c1 = emoji.charAt(0); // 获取代理对的高位 surrogate char c2 = emoji.charAt(1); // 获取代理对的低位 surrogate System.out.println(c1); // 输出类似 '?' 的符号,实际是 '\uD83D' System.out.println(c2); // 输出类似 '?' 的符号,实际是 '\uDE02' //单独看 c1 和 c2 都没有意义
codePointAt(int index)
返回指定索引处的 Unicode 代码点,如果该索引是一个代理对的起始位置,它会正确地解析并返回整个代码点的整数值。
String emoji = "😂"; int codePoint = emoji.codePointAt(0); // 从索引0开始,获取完整的代码点 System.out.println(codePoint); // 输出 128514 (这是 '😂' 的 Unicode 码位)
总结与最佳实践
| 方法 | 返回值 | 适用场景 | 备注 |
|---|---|---|---|
length() |
int (16-bit char 的数量) |
索引遍历字符串。 2. 需要知道底层 char 数组大小时。 3. 确定字符串在内存中占用的基本空间。 |
最快,但不能准确反映用户感知的字符数,对 Emoji 等无效。 |
codePointCount() |
int (Unicode 代码点的数量) |
需要计算用户能看到的“字符”数量时(如限制输入长度)。 2. 处理国际化文本、Emoji 时。 3. 需要精确处理所有 Unicode 字符时。 |
最准确,但计算成本比 length() 稍高。 |
charAt() |
char |
在确定字符不包含代理对的情况下,进行简单的字符遍历。 | 对于代理对,会返回无意义的单个 char。 |
codePointAt() |
int (Unicode 代码点) |
在遍历字符串时,正确处理包含代理对的字符。 | 推荐用于需要正确解析所有字符的遍历场景。 |
如何选择?
-
如果你只是想遍历字符串的每一个
char(进行某种简单的、不考虑语义的转换),并且不关心代理对,使用length()和charAt()是可以的。for (int i = 0; i < str.length(); i++) { char c = str.charAt(i); // 处理 c... } -
如果你需要正确处理所有 Unicode 字符,包括 Emoji,并且想得到用户感知的字符数量或正确遍历,你应该使用
codePointCount()和codePointAt()。int count = str.codePointCount(0, str.length()); System.out.println("用户感知的字符数: " + count); // 正确遍历 int[] codePoints = str.codePoints().toArray(); // 最简单的方式 for (int cp : codePoints) { // 处理代码点 cp... } // 或者手动遍历 int i = 0; while (i < str.length()) { int codePoint = str.codePointAt(i); // 处理代码点 codePoint... i += Character.charCount(codePoint); // 关键:根据代码点大小移动索引 } -
如果你需要限制用户输入的长度(比如发微博最多140个字),绝对不能使用
length(),否则用户输入一个 Emoji 就会占用两个字符,导致实际体验到的字符数远少于限制,你应该使用codePointCount()。String userInput = "今天天气真好😊"; int maxLength = 10; // 错误的做法 if (userInput.length() > maxLength) { System.out.println("输入过长!"); // "今天天气真好😊" 长度为 10,但用户感知是 9 个字符 } // 正确的做法 if (userInput.codePointCount(0, userInput.length()) > maxLength) { System.out.println("输入过长!"); // 会正确判断为超限 }
希望这个详细的解释能帮助你完全理解 Java String 的字符长度问题!
