当我指定char(来自文字或其他)时,“java内部编码是UTF16”是什么意思?它以什么编码存储在char中?

时间:2017-06-13 11:26:33

标签: java character-encoding char

//non-utf source file encoding
char ch = 'ё'; // some number within 0..65535 is stored in char. 
System.out.println(ch); // the same number output to 

“java内部编码为UTF16”。它在哪里有意义地发挥作用?

此外,我可以从代理范围(比如说'\ uD800')完美地放入char one utf16 codeunit - 使这个char完全无效的Unicode 。并且让我们留在BMP 中,所以为了避免认为我们可能有2个字符(codeunits)作为补充符号(想到这种方式听起来“char内部使用utf16”完全是胡说八道)。但也许“char内部使用utf16”在BMP中有意义吗?

如果是这样的话,我可以解决它:我的源代码文件是windows-1251编码,char literal根据windows-1251编码转换为数字(真正发生的事情),然后这个数字自动转换为另一个数字(从windows-1251号码到utf-16号码) - 这不是发生的(我是对的吗?!我可以理解为“内部使用UTF-16”)。然后写入存储的数字(实际上它是按照给定的,从win-1251编写,没有我的“从内部utf16到输出\控制台编码的虚构转换”),控制台显示它使用控制台从数字转换为字形编码(真正发生的事情)

所以这个“内部使用的UTF16编码”从未使用过吗? char只存储任何数字([0..65535]),除了特定范围和“无符号”之外没有任何差异来自int(当然我的例子范围内)???

P.S。在实验上,上面的代码使用源文件和控制台输出的UTF-8编码

й
1081

使用源文件的win-1251编码和控制台输出中的UTF-8

�
65533

如果我们使用String而不是char ...

,则输出相同
String s = "й";
System.out.println(s);

在API中,所有以char为参数的方法通常不会将编码作为参数。但是将byte []作为参数的方法通常将编码作为另一个参数。暗示使用char我们不需要编码(意味着我们确实知道这种编码)。但**我们怎么知道什么编码的东西被放入char ???

如果char只是一个数字的存储空间,我们需要了解这个数字最初来自哪个编码?**
所以char vs byte只是char有两个字节的东西用UNKNOWN编码(而不是一个字节的UNKNOWN编码的一个字节)。 给定一些初始化的char变量,我们不知道使用什么编码来正确显示它(为输出选择正确的控制台编码),我们无法分辨使用char literal初始化的源文件的编码是什么(不计算各种编码和utf可以兼容的情况)。

我是对的,还是我是一个大白痴?很抱歉在后一种情况下询问:)))

SO研究显示我的问题没有直接答案:

2 个答案:

答案 0 :(得分:0)

在大多数情况下,最好将char视为某个特定字符(与任何编码无关),例如字符' A',而不是某些编码中的16位值。只有在charString和字节序列之间进行转换时,编码才会发挥作用。

char内部编码为UTF-16这一事实只有在您必须处理它的数值时才是重要的。

代理对仅在字符序列中有意义。单个char无法保留BMP之外的字符值。这就是角色抽象崩溃的地方。

答案 1 :(得分:0)

Unicode是将文本数据表示为代码点的系统。这些通常是字符,但并非总是如此。 Unicode代码点始终以某些编码表示。常见的是UTF-8,UTF-16和UTF-32,其中数字表示 codeunit 中的位数。 (例如,UTF-8编码为8位字节,UTF-16编码为16位字。)

虽然Unicode的第一个版本只允许0 hex ... FFFF hex 范围内的代码点,但在Unicode 2.0中,他们将范围更改为0 hex 到10FFFF hex

因此,显然,Java(16位)char不再足以代表每个Unicode 代码点

这让我们回到了UTF-16。 Java char 可以表示小于或等于FFFF hex 的Unicode代码点。对于较大的代码点,UTF-16表示由2个16位值组成;一个所谓的代理对。这将适合2个Java char。实际上,Java String的标准表示是一系列char值,构成了Unicode代码点的UTF-16表示。

如果我们使用大多数现代语言(包括带有简化字符的CJK),则所有感兴趣的Unicode代码点都可以在代码平面零(0 hex 到FFFF hex )。如果您可以进行该假设,则可以将char视为Unicode代码点。但是,我们越来越多地看到更高层面的代码点。一个常见的例子是Emojis的代码点。)

如果查看String类的javadoc,您会看到一系列方法行codePointAtcodePointCount等等。这些允许您正确处理文本数据 ...以处理代理对案例。

那么这与UTF-8,windows-1251等有何关系?

这些是在操作系统级别的文本文件中使用的8位字符编码,依此类推。当您使用Java Reader读取文件时,您的文本将被有效地转码从UTF-8(或windows-1251)转换为UTF-16。当您输出字符时(使用Writer),您可以向另一个方向转码

这并不总是有效。

  • 许多字符编码(例如windows-1251)无法表示全范围的Unicode代码点。因此,如果您尝试通过配置了Windows-1251的Writer来编写(比方说)CJK字符,则会获得?个字符。

  • 如果您使用错误的字符编码读取编码文件(例如,如果您尝试将UTF-8文件读取为windows-1251,反之亦然),则转码可能会产生垃圾。这种现象非常普遍,有一个名字:Mojibake)。

你问:

  

这是否意味着在char ch ='й';文字'й'总是从编码源文件中转换为utf16?

现在我们(大概)正在讨论Java源代码。答案是,这取决于。基本上,您需要确保Java编译器使用正确的编码来读取源文件。这通常使用-encoding命令行选项指定。 (如果未指定-encoding,则使用“平台默认转换器”;请参阅javac手册条目。)

假设您使用正确的编码编译源代码(即匹配源文件中的实际表示),Java编译器将发出包含任何String文字的正确UTF-16表示的代码。

但是,请注意,这是独立的字符编码,应用程序用它来在运行时读取和写入文件 。该编码取决于您的应用程序选择的内容或执行平台的默认编码。