从String源码看Java中的编码

简介: 从String源码的一个构造方法说起public String(int[] codePoints, int offset, int count) {}what?codePoints是什么鬼?为了看懂这个源码,有必要了解一个这个codePoints(代码点)的相关知识,其实整个String源码都会不少的涉及的java编码的相关知识,比如indexOf(int ch, int fromIndex)。

从String源码的一个构造方法说起

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

what?codePoints是什么鬼?为了看懂这个源码,有必要了解一个这个codePoints(代码点)的相关知识,其实整个String源码都会不少的涉及的java编码的相关知识,比如indexOf(int ch, int fromIndex)

img_b72bf222324c35fef5c1ea1e2c387845.png
一脸懵逼

为什么会有Unicode

​ 学C/C++的时候我们知道了ASCII码,但这个能表示的字符有限,后来又出现了一些乱七八糟的编码表,Unicode就是企图统一一下编码而产生的。

Unicode的介绍

​ Unicode的第一个版本是用2个字节来编码所有的字符的,因为编码者们认为2^16=65536能容纳世界上所有语言,后来他们发现他们错了,哈哈哈,第二个版本就用4个字节来编码所有字符,这个后面说。

img_bea3dbc3aaed270db06e274576c2d1cb.jpe

先以第一个版本来说,用2个字节来编码所有字符(这个要很清晰,不然会有点懵),正好UTF-16也是这么弄的,大家误解就以为Unicode就是UTF-16。这里会涉及两个步骤,一个步骤是字符与编码一一对应的问题,如a对97,b对98如此;另一个是如何将编码的二进制这些01串保存起来的问题,这就实现了UTF(unicode transformation format),有UTF-8,UTF-16……

UTF-8与UTF-16

​ UTF16很好理解,在第一个版本的Unicode中,就是2个字节保存一个字符。UTF8就不同,它可能用1个/2个/3个来表示。那我怎么知道它用来多少个自己来表示呢?这就需要一个规定:

  1. 0开头的,就表示1个字节表示一个字符,即0xxx xxxx,如0101 0011
  2. 110x xxxx 10xx xxxx这种表示把2个字节当成一个单元,表示一个字符。
  3. 1110 xxxx 10xx xxxx 10xx xxxx这种表示3个字节当成一个单元,表示一个字符。

由上面我们可以看出UTF-8需要判断每个字节中的开头标志信息,所以如果一当某个字节在传送过程中出错了,就会导致后面的字节也会解析出错.而UTF-16不会判断开头标志,即使错也只会错一个字符,所以容错能力强.

​ 从上面可以看出,当1个字节表示一个字符时,能表示2^7=128个字符,2个字节表示时能表示2048个字符,3个单元表示时能表示65536个字符。由于"汉"的编码27721大于2048了所有两个字节还不够,只能用三个字节来表示。

接着看看第二个版本

​ 相关规定:

  • Unicode 统一编码 0x000000-0x10ffff,其中0x0000-0xffff为基本多语言平面字符

  • bmp 基本多语言平面字符,对应Unicode中0x0000-0xffff

  • Unicode码空间为U+0000到U+10FFFF,一共有17个平面,每个平面可容下65536个code point。也就是17 * 65536=1,114,112。但是其中的U+D800-U+DFFF作为UTF-16编码代理区保留,也就是它们不会作为code point分配给字符,保留数目是8 * 256=2048。

    看到这里,我们可以知道:

  • 如果在BMP级别中,那么16bits(一个代码单元)就足够表示出字符的Unicode值。

  • 那不在的呢,就属于增补字符了。那就是需要4个字节来表示,那4个字节为啥不是能表示0x00000000-0xffffffff个字符呢,只能表示到0x10ffff呢,这就有点像UTF-8的意思了,占用几个位置来表示我需要用4个字节来显示这个字符,那么需要占用多少位呢?因为只需要表示0x10 ffff - 0x10000 = 0xf ffff即可,就是20位,也就是说,虽然你给我分配4个字节32位这么多,但我只需要20位就足够表示0x10000~0x10FFFF,那剩下12位怎么办呢,这样吧,每2个字节用6位作为代理区,剩下10位用作编码,这就是U+D800-U+DFFF作为UTF-16编码代理区保留的规定了。

  • 那为什么是0xD800~0xDFFF呢,我们来看看,假设我们是编码者,我们现在要留一段来做代理区,假设我做代理区的起点选了0xD800吧,对应的是1100 1000 0000 0000,那我把剩下10位编码上去,就能表示:1101 1000 0000 0000~1101 1011 1111 1111即0xD800~ 0xDBFF,这个就算高位代理区了,然后同理,0xDC00~ 0xDFFF就算地位代理区了。

  • 好了,BMP区域有2048个编码被用作代理区了,所以它们是不能用来表示任何字符的。

Last but not least

简要的讨论了一下以String构造方法引出的一点问题,其实java的编码还是蛮复杂的,一口气说太多太复杂,估计大脑cpu也不够用了。

目录
相关文章
|
20天前
|
Java
Java开发实现图片URL地址检验,如何编码?
【10月更文挑战第14天】Java开发实现图片URL地址检验,如何编码?
48 4
|
1月前
|
Java Apache Maven
Java百项管理之新闻管理系统 熟悉java语法——大学生作业 有源码!!!可运行!!!
文章提供了使用Apache POI库在Java中创建和读取Excel文件的详细代码示例,包括写入数据到Excel和从Excel读取数据的方法。
56 6
Java百项管理之新闻管理系统 熟悉java语法——大学生作业 有源码!!!可运行!!!
|
16天前
|
Java
Java实现随机生成某个省某个市的身份证号?如何编码?
【10月更文挑战第18天】Java实现随机生成某个省某个市的身份证号?如何编码?
55 5
|
20天前
|
Java
Java开发实现图片地址检验,如果无法找到资源则使用默认图片,如何编码?
【10月更文挑战第14天】Java开发实现图片地址检验,如果无法找到资源则使用默认图片,如何编码?
49 2
|
14天前
|
Java 测试技术 开发者
Java零基础-indexOf(String str)详解!
【10月更文挑战第14天】Java零基础教学篇,手把手实践教学!
102 65
|
4天前
|
运维 自然语言处理 供应链
Java云HIS医院管理系统源码 病案管理、医保业务、门诊、住院、电子病历编辑器
通过门诊的申请,或者直接住院登记,通过”护士工作站“分配患者,完成后,进入医生患者列表,医生对应开具”长期医嘱“和”临时医嘱“,并在电子病历中,记录病情。病人出院时,停止长期医嘱,开具出院医嘱。进入出院审核,审核医嘱与住院通过后,病人结清缴费,完成出院。
20 3
|
26天前
|
存储 缓存 Java
java基础:IO流 理论与代码示例(详解、idea设置统一utf-8编码问题)
这篇文章详细介绍了Java中的IO流,包括字符与字节的概念、编码格式、File类的使用、IO流的分类和原理,以及通过代码示例展示了各种流的应用,如节点流、处理流、缓存流、转换流、对象流和随机访问文件流。同时,还探讨了IDEA中设置项目编码格式的方法,以及如何处理序列化和反序列化问题。
58 1
java基础:IO流 理论与代码示例(详解、idea设置统一utf-8编码问题)
|
9天前
|
JavaScript Java 项目管理
Java毕设学习 基于SpringBoot + Vue 的医院管理系统 持续给大家寻找Java毕设学习项目(附源码)
基于SpringBoot + Vue的医院管理系统,涵盖医院、患者、挂号、药物、检查、病床、排班管理和数据分析等功能。开发工具为IDEA和HBuilder X,环境需配置jdk8、Node.js14、MySQL8。文末提供源码下载链接。
|
12天前
|
移动开发 前端开发 JavaScript
java家政系统成品源码的关键特点和技术应用
家政系统成品源码是已开发完成的家政服务管理软件,支持用户注册、登录、管理个人资料,家政人员信息管理,服务项目分类,订单与预约管理,支付集成,评价与反馈,地图定位等功能。适用于各种规模的家政服务公司,采用uniapp、SpringBoot、MySQL等技术栈,确保高效管理和优质用户体验。
|
1月前
|
JSON 前端开发 Java
震惊!图文并茂——Java后端如何响应不同格式的数据给前端(带源码)
文章介绍了Java后端如何使用Spring Boot框架响应不同格式的数据给前端,包括返回静态页面、数据、HTML代码片段、JSON对象、设置状态码和响应的Header。
119 1
震惊!图文并茂——Java后端如何响应不同格式的数据给前端(带源码)