Java如何将一个三个字节的Unicode字符放入char类型中?

14

所以Java中的“char”占用2个字节。(可以从这里验证。)

我有这个示例代码:

public class FooBar {
    public static void main(String[] args) {
        String foo = "€";
        System.out.println(foo.getBytes().length);
        final char[] chars = foo.toCharArray();
        System.out.println(chars[0]);
    }
}

输出结果如下:

3
€

我的问题是,Java如何将一个3字节字符放入char数据类型中?顺便说一句,我正在使用参数“-Dfile.encoding=UTF-8”运行应用程序。

另外,如果我进一步编辑代码并添加以下语句:

File baz = new File("baz.txt");
final DataOutputStream dataOutputStream = new DataOutputStream(new FileOutputStream(baz));
dataOutputStream.writeChar(chars[0]);
dataOutputStream.flush();
dataOutputStream.close();

最终的文件"baz.txt"将只有2个字节,即使我将其视为UTF-8文件,它也不会显示正确的字符。

编辑2: 如果我使用UTF-16 BE编码打开文件"baz.txt",在我的文本编辑器中我将能够很好地看到€字符,这是有道理的。


3
Java内部使用UTF-16编码。参见https://dev59.com/4Wkw5IYBdhLWcg3ws833 - Thomas Stets
Char 不是一个字符;它是一个最大的问题之一,这也是 Java 的一个最大的问题。请参阅 utf8everywhere.org 以获取有关其工作原理的完整说明。 - Pavel Radzivilovsky
2个回答

10

String.getBytes()返回使用平台默认的字符编码的字节,与内部表示不一定匹配。

Java在RAM中为每个字符使用2个字节,当使用UTF-8序列化字符时,可能会在结果字节数组中产生1、2或3个字节,这就是UTF-8编码的工作原理。

您的代码示例正在使用UTF-8。 Java字符串在内存中使用UTF-16进行编码。不适合单个16位字符的Unicode代码点将使用称为代理对的2个字符对进行编码。

如果您没有向String.getBytes()传递参数值,则返回一个使用底层操作系统的默认字符集编码的字节数组。 如果您想确保使用UTF-8编码的数组,则需要改用getBytes("UTF-8")。

调用String.charAt()仅从字符串的内存存储中返回原始的UTF-16编码字符。

请查看此链接:java utf8 encoding - char,string types


8

Java使用UTF-16(16位)进行内存表示。

即使欧元符号在UTF-8中需要三个字节,但它也可以适应此格式。


2
是的,这是一个问题,因为Unicode比它还要大。现在一些Unicode代码点在Java中需要两个字符。因此,如果您使用“整个目录”,lengthcharAt的结果可能不完全令人满意。 - Thilo
那么我传递的参数 -Dfile.encoding=UTF-8 并没有真正改变什么,我们可以这么说吗? - Koray Tugay
2
该参数定义了默认的编码方式,即在未指定字符集的情况下调用getBytes()所得到的编码方式(请勿这样做,始终声明字符编码方式)。 - Thilo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接