浅聊一下Java中的char类型

简介: 浅聊一下Java中的char类型

什么是Unicode

Unicode是一种字符编码方案,它为每种语言中的每个字符都设定了统一唯一的二进制编码,也就是规定了二进制和字符的映射,以实现跨语言、跨平台进行文本转换、处理的要求,但是它并没有规定这些二进制该如何存储和传输.

掘金大佬讲Unicode

同步立场

总所周知,Java中的char数据类型采用的是UTF-16编码表示Unicode码点的代码单元,而Java字符串由char值序列组成(jdk8之前是这样的,jdk9之后就变为byte数组了).最常用的Unicode字符使用一个代码单元就可以表示,也就是两个字节,两个字节最多只能表示到6w多个字符,那么剩下的表示就需要用到辅助字符,辅助字符需要一对代码单元表示,也就是四个字节来表示.

也就是说在UTF-16中并不是说只能有两个字节,而是以两个字节为最小单元,也就是代码单元(code unit),一个代码单元包含两个字节.对于基本字符,UTF-16使用一个代码单元就能表示完全,但是对于剩下的字符,我们称之为辅助字符,辅助字符使用一对代码单元组成.

为了简化表达,在使用Unicode字符的时候通常会使用如下表达方法:

基本字符:U+0000~U+FFFF

辅助字符:U+010000~U+10FFFF

这样,就将需要使用到的字符分配成了17个平面.

这些用来表示字符的编号,我们称之为码点(code point),一个编号对应了一个具体的码点

一个码点我们表示为一个符号,这个符号可以是中文,英文,等各种文字,当然也包括 🍺 等emoji表情.常用的英文这些自然是只需要一个代码单元,但是对于 🍺 ,就需要两个代码单元.

而我们最常用的length方法返回的是采用UTF-16编码表示给定字符串所需要的代码单元数量.

下图也可以表现出length返回的是代码单元数量而非字符数量

用幼儿园知识我们都能知道平均一个emoji表情占两个代码单元.而部分中文占1个代码单元,因此这个时候,对于一个emoji表情,他的一个码点拥有两个代码单元,对于一个中文,它只有一个代码单元.

因此如果想要获得的是字符的数量,也就是码点的数量,那么应该使用codePointCount方法

你还可以使用codePoints().toArray()方法来获取字符串中的所有码点

同时,由于char类型只能装载2个字节,因此如果你给他一个辅助字符,它就会报错,因此对于这种辅助字符,我们需要使用String来装载.

API中的方法与上面知识的关系

char charAt(int index)

charAt方法我相信你一定使用过,但是如果你使用charAt方法获取到的是辅助字符中的某一个代码单元,那么返回的是乱码.

int offsetByCodePoint(int start, int cpCount)

这个方法返回的是从start这个码点开始,cpCount个码点后的码点索引,当然,他返回的是相对于代码单元数量的索引.如果你不明白,看下面的代码你就明白了

可以看到跳过1个码点返回的int值为2,也就是下一个码点的起始位置是代码单元2(代码单元从0开始,和索引差不多),因此跳过三个代码单元后,得到的是6,聪明的你一定能理解为什么说这个方法返回的是代码单元的数量了.

通过这个代码单元数量,我们可以知道一个字符串中有多少个字符

写法如下

‍IntStream codePoints()

当前方法用于返回字符串对应的码点流,通常配合toArray()方法使用来得到当前字符串对应的码点对应的UTF-16的int值.

同理,既然知道了码点的个数,我们自然也能用来判断这段文字中的字数,也就能对文字长度进行限制了.方法如下:

public String(int[] codePoints, int offset, int count)

这是String的一个构造方法,其中很明显的就展示出来了其中的一个参数需要使用到codePoints数组也就是一个码点数组,offset表示开始索引,count表示使用多少个码点.

配合上面的得到字符串长度的方法,我们就可以将所需要的包含辅助字符的数组将其变换为对应字符串了.

boolean isSupplementaryCodePoint(int codePoint)

boolean isSurrogate(char ch)

这两个方法用于判定字符是否是辅助字符


相关文章
|
18天前
|
存储 Java 编译器
深入理解 Java 泛型和类型擦除
【4月更文挑战第19天】Java泛型是参数化类型,增强安全性与可读性,但存在类型擦除机制。类型擦除保证与旧版本兼容,优化性能,但也导致运行时无法访问泛型信息、类型匹配问题及数组创建限制。为应对这些问题,可使用Object类、instanceof运算符,或借助Guava库的TypeToken获取运行时类型信息。
|
29天前
|
存储 安全 Java
大厂面试题详解:java中有哪些类型的锁
字节跳动大厂面试题详解:java中有哪些类型的锁
55 0
|
1天前
|
存储 关系型数据库 MySQL
MySQL字段的字符类型该如何选择?千万数据下varchar和char性能竟然相差30%🚀
本篇文章来讨论MySQL字段的字符类型选择并深入实践char与varchar类型的区别以及在千万数据下的性能测试
MySQL字段的字符类型该如何选择?千万数据下varchar和char性能竟然相差30%🚀
|
7天前
|
Java
Java String类型转换成Date日期类型
Java String类型转换成Date日期类型
|
8天前
|
关系型数据库 MySQL Java
Java时间转换为MySQL中的INT类型时间戳
Java时间转换为MySQL中的INT类型时间戳
|
8天前
|
Java 编译器
【Java探索之旅】解密Java中的类型转换与类型提升
【Java探索之旅】解密Java中的类型转换与类型提升
17 0
|
11天前
|
安全 Java 程序员
Java 泛型类型:变幻中的不变性
【4月更文挑战第21天】
6 1
Java 泛型类型:变幻中的不变性
|
12天前
|
XML SQL 前端开发
【Java】实体字段传参类型线上问题记录
【Java】实体字段传参类型线上问题记录
22 1
|
14天前
|
存储 Java
JAVA变量类型
JAVA变量类型
16 0
|
14天前
|
C++
【C++】std::string 转换成非const类型 char* 的三种方法记录
【C++】std::string 转换成非const类型 char* 的三种方法记录
7 0