如何理解 Java 中 String.length() 返回的是代码单元数量而非字符数量

云墨大大_4643

云墨大大_4643

2026-05-04

1004人浏览

原创

string.length() 返回 utf-16 代码单元数而非 unicode 字符数,因 java string 基于 char[] 实现,而增补字符(如 emoji)需两个 char(代理对)表示一个字符;应使用 codepointcount() 获取真实字符数。

如何理解 java 中 string.length() 返回的是代码单元数量而非字符数量

Java 中 String.length() 返回的确实是 UTF-16 代码单元(code unit)的数量,不是严格意义上的“字符数”(Unicode character count),这点容易误解,关键在于 Unicode 的编码分层和 Java 字符串的底层实现。

为什么 length() 不等于字符个数?

Java 的 String 内部用 char[] 存储,而 char 是 16 位无符号整数,对应 UTF-16 的一个代码单元。但 Unicode 字符范围远超 65536(即 0x0000–0xFFFF),超出部分(如大部分 emoji、古汉字、音乐符号等)被放在“增补平面”(Supplementary Planes),需要用两个 char(即一个代理对:high surrogate + low surrogate)来表示 —— 这就是两个代码单元,但只代表 1 个 Unicode 字符。

  • "a" → 1 个代码单元 → length() == 1
  • "中"(U+4E2D)→ 在基本多文种平面(BMP)→ 1 个代码单元 → length() == 1
  • "?"(U+1F60A)→ 在增补平面 → 需要代理对 "\uD83D\uDE0A" → 2 个代码单元 → length() == 2
  • "a?b" → 实际是 'a' + '\uD83D' + '\uDE0A' + 'b' → 4 个 char → length() == 4

怎么真正获取“字符个数”?

如果业务关心的是用户感知的“字符”数量(比如限制输入框最多 10 个表情+文字),不能依赖 length(),而应使用基于代码点(code point)的方法:

Java Maven Code Review
Java Maven Code Review

审查Java Maven项目(ZIP压缩包或GitLab仓库URL),检查代码规范、命名、模块边界、可维护性问题以及重复代码。

下载
  • str.codePointCount(0, str.length()):返回字符串中 Unicode 字符(即代码点)总数
  • str.offsetByCodePoints(0, n):用于安全地按字符索引移动(跳过代理对)
  • str.codePointAt(i):获取位置 i 开始的代码点值(int 类型),需配合 Character.isSurrogatePair() 判断是否为代理对

常见误用场景与建议

很多校验逻辑(如用户名长度限制、数据库字段截断、前端同步显示)若直接用 length(),在遇到 emoji 或生僻汉字时会出错 —— 显示上是一个图标,却被算作两个“字符”,导致提前截断或校验失败。

  • 做前端输入限制时,后端也要用 codePointCount 校验,避免绕过
  • 存入数据库前若需按字符数截断(如 VARCHAR(20)),应按代码点截取,而非简单 substring(0, 20)
  • 日志或调试时打印 length() 和 codePointCount() 对比,能快速发现增补字符影响

补充说明:它也不是字节数

有人误以为 length() 是字节数,其实完全无关。例如:

  • "abc".getBytes(StandardCharsets.UTF_8).length == 3(UTF-8 下 1 字节/字符)
  • "你好".getBytes(StandardCharsets.UTF_8).length == 6(UTF-8 下 3 字节/汉字)
  • 但两者 .length() 都是 2(因为是 2 个 BMP 汉字,各占 1 个 char)

要获取字节数,必须显式调用 getBytes(...).length,并指定字符集。

Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南

相关专题

更多
LLVM自定义Pass怎么写
LLVM自定义Pass怎么写

本专题聚焦LLVM自定义Pass开发,整理Pass类结构、run()方法、PreservedAnalyses、CMake构建、插件注册、-load-pass-plugin加载和测试用例编写流程。

2026.09.30

60

10

LLVM RISC-V参数配置教程
LLVM RISC-V参数配置教程

本专题介绍LLVM对RISC-V基础ISA和扩展的支持方式,涵盖RV32、RV64、标准扩展、实验性扩展、厂商扩展、-menable-experimental-extensions和版本差异。

2026.09.30

40

14

LLVM IR中间表示入门指南
LLVM IR中间表示入门指南

本专题整理LLVM IR的核心概念,包括中间表示作用、模块结构、函数、基本块、SSA形式、类型系统和常见语法,帮助新手理解LLVM编译流程中的关键层。

2026.09.30

40

12

PDF转图片方法
PDF转图片方法

需要把 PDF 页面用于上传、预览、分享或图片归档时,PDF 转图片方法专题整理 JPG/PNG 格式选择、逐页导出、清晰度设置、批量下载和结果检查等流程,帮助用户稳定完成 PDF 图片化处理。

2026.09.30

40

26

PixTV AI视频生成与无限画布创作
PixTV AI视频生成与无限画布创作

PixTV专题整理AI视频与视觉内容创作相关功能使用教程,涵盖AI生图、视频生成、无限画布、多模型创作、素材管理、声音音乐及视频剪辑等功能,帮助用户快速掌握PixTV从创意到成片的完整制作方法。

2026.09.29

40

15

Buffalo框架数据库开发全教程
Buffalo框架数据库开发全教程

本专题围绕Buffalo框架数据库开发,讲解database.yml多环境配置、soda与fizz迁移生成回滚、模型结构体标签、增删改查与条件查询、一对多与多对多关联、数据校验、回调钩子、事务处理及原生SQL执行能力。

2026.09.23

240

15

Buffalo框架路由与请求处理实操指南
Buffalo框架路由与请求处理实操指南

本专题讲解Buffalo框架路由与请求处理机制,涵盖路由注册与分组、资源路由、Handler编写规范、Context上下文方法、参数绑定、中间件编写挂载、Session与Cookie读写、Flash消息及错误页面定制方法。

2026.09.23

160

15

Buffalo框架零基础入门教程
Buffalo框架零基础入门教程

本专题整理Buffalo框架入门内容,涵盖Go环境准备、buffalo CLI安装、新项目生成、目录结构说明、dev热加载启动、数据库连接配置与常见报错排查,帮助新手按约定优于配置的思路跑通第一个Buffalo框架应用。

2026.09.23

120

15

Conan创建软件包配方指南
Conan创建软件包配方指南

本专题介绍通过conanfile.py创建软件包的方法,讲解包名、版本、依赖和构建设置等基础信息,以及source、build、package、package_info等常用方法的作用及编写思路。

2026.09.22

80

12

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
dev.java 官方:Learn Java
dev.java 官方:Learn Java

共0课时 | 0人学习

Java JDBC数据库连接官方教程
Java JDBC数据库连接官方教程

共0课时 | 0人学习