Java 为什么能给 char 类型赋值中文字符

4 天前
 zhouyin
java 文档里有写 一个 char 由两个自己组成 但一个 utf8 汉字由三个字节组成
为什么这样赋值没事?

char a = '我';
4260 次点击
所在节点    Java
65 条回复
moposx
4 天前
因为 char 是 16 位无符号整数,用来表示 UTF-16 码位。而 UTF-16 本身是 2 字节或者 4 字节的变长编码,“我”是在 BMP 里的,所以只需要 2 字节即可表示。如果你从扩展 B 区找一个汉字,就会发现它是不能被赋值给 char 的。
wuyiccc
4 天前
补充: char 类型不是采用 utf16 编码规则,而是描述了 UTF-16 编码中的一个代码单元
zhouyin
4 天前
@xuld
你才是菜鸟 不知道编辑器当前 utf8 编码下 输入一个汉字会插入三个字节 在源代码保存的就是三个字节 只是编译器转成了 utf16 两个字节

你其实没有理解精髓
zhouyin
4 天前
@wuyiccc
对 一般 utf16 是 4 个字节 我还在奇怪 为什么 java unicode 两个字节
zhouyin
4 天前
@wuyiccc

该字能在 java17 赋值给 char 但只能通过位移得到 2 个有用字节 如果 String.valueOf(a).getBytes("UTF-16") 则得不到有用东西

必须赋值给 String 才能处理

这个字的四个字节在此码表网站显示不出来 https://www.toolhelper.cn/Encoding/UTF16
D842 DFB7
zhouyin
4 天前
@wuyiccc
在 java16 及以上 可以把这种超出两字节的汉字 赋值给 char 但得不到正确 bytes
zhouyin
4 天前
@wuyiccc
该字通过 string.getBytes("UTF-8") 得到 4 个字节

其实它在 utf8 下

http://www.mytju.com/classCode/tools/encode_utf8.asp

是 6 个字节
zhouyin
4 天前
@wuyiccc
对应 utf8 编码 fa a0 ae b7 能在编辑器中正常显示
可能网站 mytju 给出的 utf8 不准确
w568w
4 天前
这种涉及具体设计的东西,为什么不直接看文档呢: https://docs.oracle.com/en/java/javase/22/docs/api/java.base/java/lang/Character.html#unicode

太长不看:

char 数据类型基于 Unicode 规范,该规范将字符( characters )定义为固定宽度的 16 位实体。从 U+0000 到 U+FFFF 的字符集有时被称为基本多语言平面 (Basic Multilingual Plane ,BMP)。码位大于 U+FFFF 的字符称为补充字符( supplementary characters )。UTF-16 编码这些补充字符的方式是,利用一对 16 位整数(称为「代用码位」), 第一个来自高代用值范围(\uD800-\uDBFF ),第二个来自低代用值范围(\uDC00-\uDFFF )。

因此,一个 char 值代表基本多语言平面中的一个码位,包括 UTF-16 编码使用的代用码位。为了表示那些在 UTF-16 中需要多码位编码的补充字符们(如部分汉字、符号等),将用 int 类型来代表一个完整 Unicode 码位。

因此,那些接受 char 类型的字符串工具函数,将无法处理补充字符;而接受 int 类型的那些,就可以处理所有字符。
codehz
4 天前
稍微偏个题
其实你 c 语言里也可以这么写,而且有实际用处(不过一般不是中文,而是四个英文字母组成的字面量,类似 enum State { stop = 'stop' }这样的用法,然后就可以在内存里见到这个字面量了,简易调试的时候很有用(不过有字节序的问题,所以现在也不常用)
w568w
4 天前
@w568w #29 手快发出去了。

再太长不看:char 就是 16 位整数,所以有的字符你无法赋值给 char 。int 则用于代表任意一个 Unicode 字符。Java 在 char[] 和 String 中储存字符串的方式是 UTF-16 编码。
cpstar
4 天前
你们不看字节码么?
这句代码经过编译器之后,就变成了 sipush 20320 ,管你是“你”还是什么,一律按照数字处理的,同理还有 boolean 只有 0 和 1 ,进行比较的时候其实就是判断等于 0 与否。本质都是一个数字,甚至观察 String 的本质,也是一堆 char ,一堆数字。
sagaxu
4 天前
@w568w Java 9 之后 String 内部用 byte[],编码有 LATIN1 和 UTF-16 两种
w568w
4 天前
@sagaxu #33 这我倒没了解过,有来源吗?我的断言是上面文档里的描述:

> The Java platform uses the UTF-16 representation in char arrays and in the String and StringBuffer classes.
sagaxu
4 天前
my3157
4 天前
大多数语言里面, char 都代表的是 single unicode scalar value, 而 utf8 只是编码规则, 长度是 1-4 bytes(问题中的 '我' 就会编码成 3 个 bytes), 覆盖了 BMP(基本多文种平面), 基本上够 99.99% 的各类用途, 而且 uft8 是兼容 ascii 且大小端无关的, uft16 以以上要考虑 ascii 兼容和大小端的问题
zhouyin
4 天前
@cpstar
这个帖子的初忠是 当前编辑器编码 utf8 输入汉字'你'时 输入了三个字节 E4BDA0
java 编译器隐士地把 utf8 字符字面量转成 utf16 4F60 等于十进制 20320
zhouyin
4 天前
@codehz
大佬 能不能发个具体能利用这样 enum 调试 c 的例子 不是 c 高手
LanhuaMa
4 天前
@theoriz #2 你有病,有病要去治,不治迟早会出事。
cpstar
4 天前
OP 38# 编译器干的不就是这个,读取原始文件,然后进行语法识别和语义识别,判断到给本地变量 a 设置 char ,那就把等号后边的字符(以单引号包住的,前一步语法分析没有问题的)按照文件存储编码或者-encoding 选项进行识别,按数字处理,并根据不同的数字范围来使用不同的指令集,iconst_x bipush sipush ldc 等

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://tanronggui.xyz/t/1110066

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX