Character
字符,涉及到计算机的组成原理,编码等知识,这里记录下理解的概念。
计算机常识
-
计算机只能识别 0 和 1
-
0 和 1,能表示 2 进制数
-
2 进制数能转为人类可直观阅读的 10进制数
-
人为规定每个 10 进制数字代表什么字符,就成为了编码(映射)。
-
规定不同,导致每个数字代表的字符不同,就形成了不同的编码规范,例如GBK(中国规范)、Unicode(国标)、其他国家也有自己字符的编码。
-
unicode是为了统一所有的字符而产生的。java默认采用的编码规范。
为什么会出现乱码
编码和解码方式不一致,就会导致乱码。比如通过 GBK 进行编码,数字 1 可能代表一个汉字,编码后为 2 进制数,但是如果用其他编码进行解析,例如 unicode,这个 2 进制数,代表的可能是另外一个字符,显示出来就不是最初的哪个汉字,当然如果没有这个数字对应的字符,就会出现乱码。
Unicode 基本知识
-
Unicode又称为统一码、万国码、单一码,是国际组织制定的旨在容纳全球所有字符的编码方案,包括字符集、编码方案等,它为每种语言中的每个字符设定了统一且唯一的二进制编码,以满足跨语言、跨平台的要求。
-
Unicode 字符集被分成多个区,Unicode 将“区”称为平面。Unicode 字符集被划分为 17 个平面(即,17 个区,编号为 0-16 )
-
每个平面有 216 = 65536 个代码点,每个代码点都可以代表一个字符。
-
并不是每个码点就一定对应有一个字符,因为,目前 Unicode 字符集中有很多码点都还未被使用。
-
17个平面又分为以下两类平面。基本多文种平面 ( Basic Multilingual Plane,BMP,或称为基本多语言平面、基本平面、第零平面、平面 0 ),辅助平面(或称为增补平面),每类平面都有各自划分含义,这里不深究。
-
增补字符使用两个 char 型变量来表示
-
2 类平面不做深入研究,只需要知道,javaCharacter 类中有很多方法来检测码点属于哪个平面。
-
码点空间,从 0 到上限值之间的范围称为码点空间,例如 Unicode 基本平面的空间为 0 ~ 65535
-
代码点(Code Point,简称码点)和码点值,codePoint 在 Character 类中常出现。码点是指码点空间中的一个位置,该位置所代表的数值就是码点值
Character.java 源码解析
(1)很多静态常量
都是一些 Unicode 规范的类别分类,知道即可。
(2)很多判断方法
多数用于判断码点的类型、属于哪个平面、是否是某一个类型。
(3)一些常规的方法
比较,toString、hashCode等
(4)重要的内部类
UnicodeBlock、UnicodeScript
UnicodeBlock 主要是一个静态 map 集合,键是字符串,代表哪一类字符,值是 UnicodeBlock。例如中日韩的字符, CJK_SYMBOLS_AND_PUNCTUATION
UnicodeScript:是一个枚举,Unicode script 分类。
(5)重要的字段
blockStarts,这是一个 int 数组。每一个数字都是某一类字符的起始数字,上一类字符的结束数字。例如,下标为 0 的数字是 0x0000,下标为 1 的数字是 0x0080,则 0000..007F 代表 Basic Latin,依次类推,每个相邻的下标数字范围代表一类字符。
(6)字符缓存
CharacterCache,静态内部类,缓存了0到127,共128个字符。
(7)2 分查找法
public static UnicodeBlock of(int codePoint) {
if (!isValidCodePoint(codePoint)) {
throw new IllegalArgumentException();
}
int top, bottom, current;
bottom = 0;
top = blockStarts.length;
current = top/2;
// invariant: top > current >= bottom && codePoint >= unicodeBlockStarts[bottom]
while (top - bottom > 1) {
if (codePoint >= blockStarts[current]) {
bottom = current;
} else {
top = current;
}
current = (top + bottom) / 2;
}
return blocks[current];
}
扩展
CharacterData0E、CharacterData00、CharacterData01、CharacterData02、CharacterDataLatin1、CharacterDataPrivateUse、CharacterDataUndefined
这些类都是对字符进行定义操作的一些类,实际用处不大,了解即可。
一些方法解析
// 最大值,其二进制是 16 个 1.
public static final char MAX_VALUE = '\uFFFF';
// 使用移位运算,小于 max_value 的数字,右移 16 为都应该为 0
public static boolean isBmpCodePoint(int codePoint) {
return codePoint >>> 16 == 0;
// Optimized form of:
// codePoint >= MIN_VALUE && codePoint <= MAX_VALUE
// We consistently use logical shift (>>>) to facilitate
// additional runtime optimizations.
}
// 同理,判读一个数字是否在一个范围内,都进行右移 16 位,然后比较大小
public static boolean isValidCodePoint(int codePoint) {
// Optimized form of:
// codePoint >= MIN_CODE_POINT && codePoint <= MAX_CODE_POINT
int plane = codePoint >>> 16;
return plane < ((MAX_CODE_POINT + 1) >>> 16);
}
如何获取字符其 codepoint ?
char anyChar = '你';
int number = (int) anyChar;
System.out.println(number);