Java | char

猜一下这段java 代码结果输出什么?

System.out.println("".length());

Unicode 字符定义

Unicode 定义了全球所有文字(字符)的编码标准,一个字符对应一个编码(数字)。最开始使用2个字节来表示所有字符,这也是为什么java char 使用两个字节来表示字符的原因,但是2个字节不能完全表示所有的字符,所以编码后面扩展到了3个字节。
1、 基本字符表示从 U+0000 到 U+FFFF 之间的字符集,也被成为基本多语言面(BMP)
2、增补字符表示从 U+010000 到 U+10FFFF 范围之间的字符集。

March 2020, there is a repertoire of 143,859 characters.
Private Use Area: U+E000–U+F8FF (6,400 characters).
Supplementary Private Use Area-A: U+F0000–U+FFFFD (65,534 characters).
Supplementary Private Use Area-B: U+100000–U+10FFFD (65,534 characters).

unicode 编码扩展了,java 的char 怎么办,表示不了了?

The Java platform uses the UTF-16 representation in char arrays and in the String and StringBuffer classes. In this representation, supplementary characters are represented as a pair of char values, the first from the high-surrogates range, (\uD800-\uDBFF), the second from the low-surrogates range (\uDC00-\uDFFF).

java 默认使用UTF-16 来进行unicode 编码,如果unicode 大于了2个字节,java 使用两个char 来表示。上面示例中 “” unicode == U+10400,所以会被解析成两个char。

Unicode 相关术语

character :
书写系统中文本的最小表示单元

character set :
character 集合

code point:
代码点,unicode 字符对应的编码的数字,比如U+10400 就是一个代码点

code space :
unicode 代码点的范围,U+0000 -- U+10FFFF

code unit :
对代码点进行二次编码的最小单位(1 byte,2 byte ,4 byte),一个字符可能由多个code unit 编码组成,见后续unicode 实现。

codepage、codemap:
表示码表,编码与字符的映射关系

Unicode 实现

Unicode 标准定义了一个字符对应一个数字,这个数字可以是2个字节,也可以是3个字节。我们程序要对这个数字进行解析,就需要判断是2个字节组成一个字符,还是三个字节组成一个字符。常用的编码方式有 UTF-8、 UTF-16、 UTF-32,如果是需要在网络中传输,还需求定义大端小端。

UTF-8

code unit 为1个字节,UTF-8 编码unicode 后结果为1-4 个字节,这样我们就可以从第一个字节来判断后续还有多少个字节。


UTF-8.png
UTF-16

code unit 为2个字节,UTF-16编码unicode 后结果为 2、4 个字节


UTF-16.png
UTF-32

code unit 为4个字节,UTF-32编码unicode 后结果为 4 个字节

例如:
"abc" U+10400

 UTF-8编码:61, 62, 63, f0, 90, 90, 80
 UTF-16编码:0061, 0062, 0063, d801, dc00
 UTF-32编码:00000061, 00000062, 00000063, 00010400
Java 字符集实现

java 源文件编码可以定义文件编码方式 ,比如gbk,utf-8,utf-16。java编译器把java 源文件统一编译成unicode(UTF-16)格式存储。可以使用 javac -encoding encoding 自定源文件的编码。

java 是怎么实现编码格式的转换的呢?
java 会对每一种字符集编码与unicode 编码做一个对应关系,这样只要我们知道任何一种编码,都能够转换为unicode 编码。

例如 GBK
b2cStr :就是一个codepage (码表),里面定义所有中文字符与unicode的对应关系。


b2cStr.png
b2cStr.png

b2cStr 为什么定义一个字符数组,因为gbk 编码 为一个数组 例如娩 编码为C3E4,用数组可以方便映射。


GBK 编码举例.png

代码测试

 Charset charset =Charset.forName("gbk");
    ByteBuffer buffer = ByteBuffer.wrap(new byte[]{(byte)0xc3,(byte)0xe4});
    CharBuffer decode = charset.decode(buffer);
    IntStream chars = decode.chars();
    chars.forEach(i->{
      //ux5a29
      System.out.println(i);
    });
    System.out.println(charset.decode(buffer));

输出

char 的值0x5a29 对应的unicode 编码也为娩


娩.png
输入法与字符集

1、输入法 依据键盘点位查找操作系统对应的字符集,并且找到字符集对应的编码
2、输入法把codepoint 传递给应用程序,应用程序按照指定编码方式对codepoint 进行编码
3、应用程序编码后,存储到磁盘。

比如在windows 系统中,我们可以自定义字符,然后关联一个codepoint ,输入法选择使用codepoint 方式输入。输入对应的codepoint 后,就可以显示为自己构造的字符。应用程序接受到codepoint 后,按照指定的编码方式进行编码。

参考资料:

https://en.wikipedia.org/wiki/Unicode
http://unicode.org/glossary/#coded_character
https://en.wikipedia.org/wiki/Glyph
https://en.wikipedia.org/wiki/Character_encoding
https://en.wikipedia.org/wiki/GBK_(character_encoding)
http://www.khngai.com/chinese/charmap/tblgbk.php?page=0
http://tools.jb51.net/table/gbk_table
https://docs.oracle.com/javase/7/docs/api/java/lang/Character.html

你可能感兴趣的:(Java | char)