从String源码看Java中的编码

2018-01-12  本文已影响39人  李不言被占用了

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

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

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

一脸懵逼

为什么会有Unicode

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

Unicode的介绍

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

先以第一个版本来说,用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了所有两个字节还不够,只能用三个字节来表示。

接着看看第二个版本

​ 相关规定:

Last but not least

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

上一篇下一篇

猜你喜欢

热点阅读