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

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

char a = '我';
4264 次点击
所在节点    Java
65 条回复
9LCRwvU14033RHJo
4 天前
为什么很多人说 char 是 utf-16 编码呢? char 存的是 unicode 不是 utf-8 或者 utf-16 。它能存 65536 个基本多文种平面( BMP )的字符,如果超过这个范围(生僻字)就需要两个 char 才能存得下。

char c = '\u0041';
System.out.println(c); // 输出:我
9LCRwvU14033RHJo
4 天前
@user8341
更正:
char wo = '\u6211';
System.out.println(wo); // 输出:我
zhouyin
4 天前
@user8341
超过这个范围就必须要用 String
没有两个 char 的表示法吧
llej
4 天前
我超市了一下,在两个字节能够表示的是可以直接这样赋值的,但超出了就会报错。

所以好像没啥问题,赋值中文确实可能出错,只是你的用例没到边界情况

```java
class Main {
public static void main(String[] args) {
// 创建一个包含超出基本多文种平面( BMP )字符的字符串
char str = '𠜎';

System.out.println("字符串: " + str);
}
}

```
llej
4 天前
@zhouyin 因为他本来就不是用的 utf8 ,java 用的就是 utf16 呀,这个和你代码文件的编码无关的,假设你使用 gbk2312 来保存你的代码,java 解析加载之后还是按他自己的规则走的。
zhouyin
4 天前
@llej
你这样不行的 这种字符 赋值给 char 控制台输出乱码
WorseIsBetter
4 天前
@codehz #30

但这种写法按标准[^1]会得到一个「实现定义」的值。

> The value of an integer character constant containing more than
> one character (e.g., 'ab'), or containing a character or escape
> sequence that does not map to a single-byte execution character,
> is implementation-defined.

考虑到可移植性,通常不建议使用。
除非你写的代码只应用于特定实现,且该实现对此有明确定义。

比如在 GCC[^2] 中:

> The compiler evaluates a multi-character character constant
> a character at a time, shifting the previous value left by the
> number of bits per target character, and then or-ing in the
> bit-pattern of the new character truncated to the width of a
> target character.

[^1]: ISO/IEC 9899:1999 §6.4.4.4/10
[^2]: https://gcc.gnu.org/onlinedocs/cpp/Implementation-defined-behavior.html

---

声明:本回答并非使用 LLM 生成。
cpstar
4 天前
@llej 44#
复制到 intelliJ 里直接就是两个\u ,在 uestudio 中可以显示“𠜎”,按照 UTF-8 保存,javac -encoding UTF8 编译报错。按照 UTF-16 保存,并且-encoding UTF16 ,同样。
45#
在编译阶段,可以指定代码来识别源代码文件格式。典型的问题就是 Windows 环境如果按照 utf-8 编辑文件,但是手工在 cmd 里编译的话,会按照 GBK 识别文件从而在中文字符上出问题。
dandycheung
4 天前
@sagaxu 你说的这是另外一件事。Windows 下,一个 Unicode 字符也是两个字节,你说是怎么做到的?当然是用更复杂的其它方法。
zhouyin
4 天前
@cpstar
这种奇怪字符无法显示跟当前终端编码无关 gitbash 是 utf8 也无法显示 System.out.println("" + char )

除非这个 char 是 65535 里面的 那种生僻字符就无法显示

你如果能显示 是因为 jvm 实现由差别 因为 char 最多只能两个字节 那种生僻字符占 4 个字节
sagaxu
4 天前
@dandycheung 做不到的,10 万+字符携带的信息量,不可能编码进 2 字节中,Windows 一个 Unicode 字符也可能是 4 字节。UTF-16 对应的不是字符,可能是半个字符。
dandycheung
4 天前
@sagaxu 对,UTF-16 的方法叫“代理对”,surrogate pair ; Windows 的原生 Unicode 方案不是 UTF-16 ,而是叫 UCS2 ,虽然在大部分代码点上跟 UTF-16 重合,但并不完全一样。但是这些,都不影响楼主那个问题应该如何理解。
iseki
4 天前
Java 的 char 存储的是 UTF-16 的一个 code unit ,一个不在 BMP 的 code point 在 UTF-16 里是两个 code unit ,所以你没法把这部分字符塞进一个 char 。但是常用汉字都在这个范围。
zhouyin
4 天前
@sagaxu
10 万个字符算啥

utf-16 能用 4 个字节编码所有字符
就是 4294967296 个字符 42 亿 9 千 4 百 9 十 6 万 7 千 2 百 9 十 6 个字符!
moposx
4 天前
@zhouyin 4 字节定长编码方案很早就有了。虽然简单,但由于空间占用和兼容性两方面的问题没能得到大规模应用。另外 Unicode 的编码空间范围是 0x0000 到 0x10FFFF ,远低于理论上限
glcolof
4 天前
@zhouyin 这得看编辑器内部以什么字符编码工作的,比如在 Windows 平台,Windows 自带的文本输入框内部用的就是 ucs2/utf-16 ,所以输入法输入的也是 ucs2/utf-16 ,一个汉字两个字节。
zhouyin
4 天前
@glcolof
还要看编辑器啊 输入法是跟编辑器编码对应的 不然为什么不同编码时输入的汉字 保存后字节不一样

难道保存时临时转编码?
glcolof
3 天前
@zhouyin 对,读取和保存时转编码。一般语言的运行时库会提供相应的功能,指定使用什么编码。
seyoatda
3 天前
@9LCRwvU14033RHJo #41 首先区分字符集和字符编码。Unicode 是字符集。要存到数据中是要指定编码的。准确的说:Java 中的 char 存放的是用 utf-16 编码的 Unicode 。
Belmode
3 天前
我只能说,基础不牢,地动山摇......

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

https://tanronggui.xyz/t/1110066

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

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

© 2021 V2EX