0

0

Java 中 char 和 String 的细节和使用注意

阿神

阿神

发布时间:2016-11-07 17:18:03

|

1880人浏览过

|

来源于php中文网

原创

char 数据类型的使用注意

java 中使用 char 数据类型来表示字符,但是 char 类型并不能表示一切字符。

Unicode 字符集

首先需要知道我们在 Java 中使用的是 Unicode 字符集。在其出现之前有已经有了很多字符集,如 ANSI、GB2312 等等。由于存在众多标准不同的字符集,这就导致了两个问题:

  • 对于任意给定的一个代码值,在不同的字符集中可能对应不同的字符;

  • 采用大字符集的语言其编码长度可能不同,如对常用字符采用单字节编码,而其他字符采用多字节编码。

Unicode 字符集的出现就是为了统一编码,消除以上的问题。所谓字符集就是一个由众多不同的字符组成的集合。Unicode 字符集对每一个字符都分配了一个唯一的 代码点(code point) 用来标识字符本身。所谓代码点就是一个添加了 U+ 前缀的十六进制整数,如字母 A 的代码点就是 U+0041。

立即学习Java免费学习笔记(深入)”;

有了Unicode 字符集后,我们要考虑的就是以什么样的方式对这些字符进行传输和存储,这就是 Unicode 编码的实现方式,我们称为 Unicode 转换格式(Unicode Transformation Format,简称 UTF)。我们熟悉的 UTF-8、 UTF-16 等就是不同的 Unicode编码实现方式。

在 Unicode 字符集诞生之初,采用 UCS-2(2-byte Universal Character Set) 这种定长的编码方式对 Unicode 字符集进行编码,这种方式采用 16 bit 的长度来进行字符编码,所以最多可以对 2^16 = 65536 个字符进行编码(编码范围从 U+0000 ~ U+FFFF)。在当时的情况下,设计者们用了不到一半的数量就对所有字符进行了编码,并且认为剩余的空间足够用于未来新增字符的编码。

不幸的是,随着中文、日文、韩文等表意文字不断的加入,Unicode 字符集中的字符数量很快超过了 16 位所能编码的最大字符数量,于是设计者们对 Unicode 字符集进行了新的设计。

新的设计将字符集中的所有字符分为 17 个 代码平面(code plane)。其中 U+0000 ~ U+FFFF 这个代码点范围被划定为 基本多语言平面(Basic MultilingualPlane,简记为 BMP),其余的字符分别划入 16 个 辅助平面(Supplementary Plane),代码点范围为 U+10000 ~ U+10FFFF,这些处于辅助平面的字符我们称作 增补字符(supplementary characters)。

在 Unicode 字符集中的字符被重新划分到不同平面后,需要注意以下两个方面:

  • BMP 范围内的字符和 UCS-2 下的字符编码基本保持一致,但是 BMP 中的 U+D800 ~ U+DFFF 部分被留空,不分配给任何字符,作用是用于给辅助平面内的字符进行编码。

  • 不是每个平面内的每个位置都被分配给了指定的字符,原因是:

  • 特殊用途,如 BMP 中的 U+D800 ~ U+DFFF 部分;

  • 作为保留空间

  • 没有足够的字符

UTF-16

UTF-16 同样使用 16 bit 的编码来表示 Unicode 字符,也就是说 UTF-16 的 代码单元(code unit) 为 16 位。代码单元指的是字符编码的一个最基本单元,即任意一个字符必然是由 n(n≥1) 个代码单元组成的。

在 UTF-16 下,由于 16 位长度只能表示 65536 个字符,所以就默认映射所有在 BMP 范围内的字符,由此 U+D800 ~ U+DFFF 这个部分就留空了,那么辅助平面的字符也就能借助这个留空的部分来表达。这就是 UTF-16 设计的巧妙之处,在不浪费空间的情况下解决所有字符的编码问题。

那么怎么表达辅助平面的字符呢?其实就是将辅助平面字符的代码点编码为 一对 16 bit 长的代码单元,称之为 代理对(surrogate pair),而代理对必然落在 BMP 中的 U+D800 ~ U+DFFF 部分。这样就解决了用 16 位的代码单元编码整个 Unicode 字符集的问题。需要注意的是 U+D800 ~ U+DFFF 这个部分我们可以称作 代理区,其中 U+D800 ~ U+DBFF 这个部分称为 高位代理区(前导代理区),U+DC00 ~ U+DFFF 这个部分称为 低位代理区(后尾代理区)。

下面通过将 U+64321 这个处于辅助平面的字符进行 UTF-16 编码的实例来讲解辅助平面字符的编码方式。

首先将这个字符的代码点减去 0x10000,得到长度为 20 bit 的一个值,这个值的范围必然在 0x0000 ~ 0xFFFF之内。

1.png

Whimsical
Whimsical

Whimsical推出的AI思维导图工具

下载

将 Vx 的高位 10 bit 的值作为高位代理的运算基数 Vh,将低位 10 bit 的值作为低位代理的运算基数 Vl。这两个 10 bit 的值的取值范围都必然在 0x0000 ~ 0x3FF 之间。

2.png

将 Vh 和 Vl 分别与高位代理区和低位代理区起始位置的代码点进行 按位或 运算,得到的结果就是这个处于辅助平面的字符 U+64321 的 UTF-16 编码。

3.png

所以最终 U+64321 这个字符就被编码成了由高位代理和低位代理组成的一个代理对,我们需要同时用 0xD950 和 0xDF21 来表示这个字符。

通过上面的例子我们可以看到,任何辅助平面内的字符在 UTF-16 下都会被编码为由两个长度为 16 位的代理编码组成的代理对,在程序中表示这个字符时,需要占用的就不再是 16 位的空间,而是 32 位。

不建议在 Java 程序中使用 char 数据类型

经过上面对 Unicode 字符集和 UTF-16 的讲解,我们现在来讨论为什么不建议在 Java 程序中使用 char 数据类型。

由于 Java 采用的是 16 位的 Unicode 字符集,即 UTF-16,所以在 Java 中 char 数据类型是定长的,其长度永远只有 16 位,char 数据类型永远只能表示代码点在 U+0000 ~ U+FFFF 之间的字符,也就是在 BMP 内的字符。如果代码点超过了这个范围,即使用了增补字符,那么 char 数据类型将无法支持,因为增补字符需要 32 位的长度来存储,我们只能转而使用 String 来存储这个字符。

4.png

如上编写的代码,使用 char 数据类型来保存辅助平面的字符,编译器将会报错 Invalid character constant。

随着互联网用户的不断增多以及互联网语言的不断丰富,用户越来越高频率的在互联网上使用一些特殊字符来表达丰富的语义,而这些字符很有可能是属于辅助平面里的增补字符,所以如果我们使用 char 类型来进行处理,就很有可能减低我们程序的健壮性。

String 的细节

获取字符串长度

String 是我们在编程时使用的非常多的数据类型,它用来表示一个字符串。查看 String 的源码,我们可以看到其底层实际是使用一个 char 类型数组在存储我们的字符。

5.png

我们也知道调用其 length() 方法可以得到字符串的长度,即字符串中字符的数量。其实现是直接返回底层 value 数组的长度,代码如下:

7.png

结合我们上面对于字符编码的知识,我们知道 Java 中 char 的长度永远是 16 位,如果我们在字符串中使用了增补字符,那就意味着需要 2 个 char 类型的长度才能存储,对于 String 底层存储字符的数组 value 来说,就需要 2 个数组元素的位置。所以下面的这个程序我们将得到一个意料之外的结果:

8.png

按照我们的想法,字符串 tt 中应该只有 8 个字符,然而实际输出却是 9 个。上面我们已经讲过 Java 采用的是 16 位的 Unicode 字符集,所以在 Java 中一个代码单元的长度也是 16 位。一个增补字符需要两个代码单元来表示,所以 tt 字符串中的字符 

java速学教程(入门到精通)
java速学教程(入门到精通)

java怎么学习?java怎么入门?java在哪学?java怎么学才快?不用担心,这里为大家提供了java速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
Java 桌面应用开发(JavaFX 实战)
Java 桌面应用开发(JavaFX 实战)

本专题系统讲解 Java 在桌面应用开发领域的实战应用,重点围绕 JavaFX 框架,涵盖界面布局、控件使用、事件处理、FXML、样式美化(CSS)、多线程与UI响应优化,以及桌面应用的打包与发布。通过完整示例项目,帮助学习者掌握 使用 Java 构建现代化、跨平台桌面应用程序的核心能力。

37

2026.01.14

php与html混编教程大全
php与html混编教程大全

本专题整合了php和html混编相关教程,阅读专题下面的文章了解更多详细内容。

19

2026.01.13

PHP 高性能
PHP 高性能

本专题整合了PHP高性能相关教程大全,阅读专题下面的文章了解更多详细内容。

37

2026.01.13

MySQL数据库报错常见问题及解决方法大全
MySQL数据库报错常见问题及解决方法大全

本专题整合了MySQL数据库报错常见问题及解决方法,阅读专题下面的文章了解更多详细内容。

19

2026.01.13

PHP 文件上传
PHP 文件上传

本专题整合了PHP实现文件上传相关教程,阅读专题下面的文章了解更多详细内容。

16

2026.01.13

PHP缓存策略教程大全
PHP缓存策略教程大全

本专题整合了PHP缓存相关教程,阅读专题下面的文章了解更多详细内容。

6

2026.01.13

jQuery 正则表达式相关教程
jQuery 正则表达式相关教程

本专题整合了jQuery正则表达式相关教程大全,阅读专题下面的文章了解更多详细内容。

3

2026.01.13

交互式图表和动态图表教程汇总
交互式图表和动态图表教程汇总

本专题整合了交互式图表和动态图表的相关内容,阅读专题下面的文章了解更多详细内容。

45

2026.01.13

nginx配置文件详细教程
nginx配置文件详细教程

本专题整合了nginx配置文件相关教程详细汇总,阅读专题下面的文章了解更多详细内容。

9

2026.01.13

热门下载

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

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Kotlin 教程
Kotlin 教程

共23课时 | 2.5万人学习

C# 教程
C# 教程

共94课时 | 6.7万人学习

Java 教程
Java 教程

共578课时 | 46.1万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号