1

由char和byte的关系引申出去——总结一下java中的字符编码相关知识 - legolas-PRC

 1 year ago
source link: https://www.cnblogs.com/legolas-PRC/p/17028751.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

由char和byte的关系引申出去——总结一下java中的字符编码相关知识

一、字符编码

手持两把锟斤拷,口中直呼烫烫烫

​   在文章伊始,先来复习一下计算机中关于编码的一些基础知识,着重理清以下几个基本概念。

1. 码点(code point)

​   计算机只能以二进制的形式存储文字,故而计算机中每一个字母,文字,符号,emoji都对应着一个二进制数,而这个二进制数就是码点

2. 字符集

​   光有码点还不够,我们还得知道有哪些码点,这些码点又能表示哪些字符,于是便又到了喜闻乐见的制定标准环节。标准所支持的所有字符及其对应码点的集合被称为字符集。例如学过C语言的同学都知道的ASCII字符集,它共包含了128个字符,包括数字,26个字母的大小写及一些符号,对应的码点就是0-127。再有就是后面要提到的Unicode字符集。

​   以ASCII字符集为例,它的码点为0-127,最大不超过7bit,而计算机中一般是以8bit的字节(byte)为单位。出于种种考量,实际存储在计算机中的码点的二进制都会在头部添0,以8bit存储。例如A对应码点65,二进制为100 0001,实际在计算机中存储为0100 0001。这种在计算机中实际存储的内容到字符的映射就是编码。

​   我们熟悉的编码方式有ASCII,UTF-8,UTF-16,欧洲的ISO,中国大陆的GBK等等。计算机中存储的同一段二进制,用不同的编码方式,会得到完全不同的内容。

4. Unicode字符集

​   ASCII一共只包含了128个字符,显然不够用,于是便有了Unicode字符集。Unicode字符集中收录了世界上绝大多数文字,符号等,反正就是非常多。

​   行文至此,笔者想到自己当初学习时的一个疑惑,即字符集已经规定好了字符到码点的映射,为啥还有各种不同的编码方式。如果读者仔细理解了上文不难发现,在计算机中以何种方式存储码点是需要编码来确定。最简单的方法就是直接将码点转成二进制存储,比如对ASCII字符集的ASCII编码,对Unicode的UTF-32编码。

​   由于Unicode字符集数量极其旁大,单个字符最大已超过了3个字节(具体多大我也不清楚,目前用4个字节还足够表示),同时为了区分前后两个字符在哪里断开,utf-32编码简单粗暴得将每个字符以32位4字节的形式存储在计算机中。这样很好理解,但带来了严重的空间浪费,对于常用的字母得要存一堆0,简直就是0溢事件。

5. UTF-8编码

​   我们常见的utf-8便是为了解决上述问题而诞生的,他是针对于Unicode的可变长度编码方式,可以把不同字符以1,2,3,4字节大小存储到计算机中,同时utf-8兼容ascii,具体规则参考下图,也推荐大家看一下图片下方链接的视频,讲的很好:

2524445-20230105194810368-716979256.png

图片来源:【你懂乱码吗?锟斤拷烫烫烫(详解ASCII、Unicode、UTF-32、UTF-8编码)】 https://www.bilibili.com/video/BV1xP4y1J7CS/?share_source=copy_web&vd_source=f5db843fce15b7c3e2990f4f7a6e8921

二、Java中的字符编码

1. 编码方式:

​   有了以上知识的铺垫,其实接下来的问题就很好解决了。

​   首先,java中采用的是基于Unicode字符集的UTF-16编码方式。utf-16可以将不同字符以2或4字节大小存储在计算机中,可能有同学已经发现规律了,utf-8是以8bit为最小单位,而utf-16是以16 bit为最小单位,而这个最小单位实际上就是所谓的代码单元(code unit)

2. char类型:

​   基本类型char类型就是一个16bit的代码单元。我们日常里常用的字符,如字母,汉字等只需要一个char,而对于一些类似于emoji这样的码点值很大的字符,需要两个char。

​   java中char类型的字面量用'A'单引号括起来,表示一个字符常量。对于一些特殊字符,如回车,换行,我们要用到转义字符来表示,如下图:

2524445-20230105194846828-1985968484.png

图片来源:《java核心技术卷Ⅰ》

3. 应用:

​   行文至此,笔者又想起之前曾经看到过的一个相关的案例。

​   简言之就是需要对数据库中取出的用户名做一个截断,比如某些情况下只需要呈现用户名的前三个字。而这个系统允许用户上传的用户名中包含emoji表情。

​   在这种情况下就要注意了,一个emoji字符由两个char组成,如果简单得用String.subString()或者String.length是有问题的,因为这些方法都是以char为单位,可能会造成把一个emoji字符只截了一个char出来,从而导致问题。在这里就需要用String的codePoint相关的方法去截取,以码点为单位,因为一个码点一定代表一个字符,而一个char则未必。

​   详情见该视频:【Emoji 表情导致线上故障2个小时。老板直接损失10万。到底是什么问题?| 故障复盘 | 实战经验分享】 https://www.bilibili.com/video/BV1MG41177pT/?share_source=copy_web

三、 总结:

​   如果您坚持看到了这里,那么我想一定已经对于我标题提出的问题的答案了然于胸了。

​   char和byte的关系,现在看来这俩也没啥关系嘛,只能说我这个引申不是很合适。本文着重介绍了计算机字符编码的相关知识,同时也总结了java中有关字符编码的一些内容,希望能对你有所帮助。

四、 参考资料:

  1. 【你懂乱码吗?锟斤拷烫烫烫(详解ASCII、Unicode、UTF-32、UTF-8编码)】 https://www.bilibili.com/video/BV1xP4y1J7CS/?share_source=copy_web&vd_source=f5db843fce15b7c3e2990f4f7a6e8921
  2. 《java核心技术卷Ⅰ》

鄙人只是一名在读的软件工程专业的本科生,正在复习找工作,故而将复习时遇到的一些有意思的东西总结出来,既是加深理解,也是便于日后复习。

鄙人才疏学浅,若文中有谬误之处,还望诸位不吝斧正,以免误人子弟。若有同道中人想一同讨论学习,也可以联系我=>[email protected]。未经本人同意,请勿转载!

路漫漫其修远兮,吾将上下而求索。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK