java string 实现_JAVA的String的实现

一。Unicode和UTF-16

要说String必然跑不掉Unicode。简单说Unicode是一种字符集,说白了就是每个字符分配了一个数字与之对应。其范围是U+0000到U+10FFFF。

再来说两个概念叫代码点(Code Point)和代码单元(Code Unit)。

代码点:指的就是Unicode的中每个字符对应的数值,范围在U+0000到U+10FFFF之间。

代码单元:就是用来表示unicode的数值时采用的编码的最小单位,UTF-8就是8位即一个字节,UTF-16就是2个字节,UTF-32就是4个字节。

UTF-8的代码单元是一个字节,要存储Unicode就必须采用一定编码方式即

000000 - 00007F

0zzzzzzz(00-7F)

1个字节

000080 - 0007FF

110yyyyy(C0-DF) 10zzzzzz(80-BF)

2个字节

000800 -00FFFF

1110xxxx(E0-EF) 10yyyyyy 10zzzzzz

3个字节

010000 - 10FFFF

11110www(F0-F7) 10xxxxxx 10yyyyyy 10zzzzzz

4个字节

UTF-16的代码单元是两个字节,编码方式

000000-00FFFF

xxxxxxxx xxxxxxxx yyyyyyyy yyyyyyyy

2个字节

010000 - 10FFFF

110110yyyyyyyyyy 110111xxxxxxxxxx

4个字节

二。String内部的实现。

String中实际数据的存储就是Unicode的UTF-16的编码形式。所以代码单元是2个字节,这也符合char的大小。现在有个很明显的问题就是Unicode的范围是U+0000到U+10FFFF,而一个char没法表示U+10000到U+10FFFF之前的数值,为了解决这个问题就采用了上面介绍的两个char来组合表示这个范围的值。

分拆的规则是10000到10FFFF,按照最大值算一共占了20位,高10位的值加上0xD800后存在一个char中,低10位的值加上0xDC00存在一个char中,这样两个char组合起来表示一个超过10000的unicode编码值。即 U+0000到U+FFFF用一个char表示,这部分叫基本多语言平面(BMP Basic Multilingual Plane)。ps:绕口得绕死了。U+10000到U+10FFFF用两个char表示,这部分叫辅助平面(Supplementary Planes)。

看似上面解释的很好,其实还有一个问题。当遇到一个2个char组成的Unicode编码时,怎么知道何时解析成一个,何时解析成两个单独的Unicode编码。其实就是说 如果存在一个char的和两个char在表示的时候 如果存在重复前缀的时候该怎么区分出来?例如如果一个char值是 '\uD869',两个char的是'\uD869'和'\uDEA5',就会出现无法唯一解析的问题,是把'\uD869'和'\uDEA5'当成两个单独的unicode来解析呢?还是当成一个整体的unicode来解析呢?其实这个问题unicode在制定编码的时候就考虑了,解决方案就是Unicode标准规定U+D800到U+DFFF的值不对应于任何字符。这样只要遇到在U+D800和U+DFFF之间的char,就知道下一个char跟这个是一体的,不能分别拆开解析,必须两个char一起解析。

知道上面这些后其实对于String的底层存储就比较容易理解了。String内部是定义了几个主要的基本数据类型。

private final char value[]; //存储unicode值,不过是以UTF-16编码的方式存储。

private final int offset; //对于第一个字符与数组的偏移量。

private final int count; //String中代码点的个数。

private int hash; //缓存Hash值

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值