Java';字符串的本机字符集

Java';字符串的本机字符集,java,utf-8,character-encoding,utf-16,Java,Utf 8,Character Encoding,Utf 16,我完全被我在电视上看到的答案弄糊涂了 java文档上的stackoverflow plus 虽然上面链接中的文档和堆栈中的所有理论似乎都指出UTF-16是Java支持的本机字符集,但还有一种理论认为它取决于JVM/OS,例如在link中,它说: Java虚拟机的每个实例都有一个默认字符集,它可能是标准字符集之一,也可能不是。默认字符集在虚拟机启动期间确定,通常取决于基础操作系统使用的区域设置和字符集 然后在另一节的同一链接中,它说 Java编程语言的本机字符编码是UTF-16 我发现很

我完全被我在电视上看到的答案弄糊涂了 java文档上的stackoverflow plus

虽然上面链接中的文档和堆栈中的所有理论似乎都指出UTF-16是Java支持的本机字符集,但还有一种理论认为它取决于JVM/OS,例如在link中,它说:

Java虚拟机的每个实例都有一个默认字符集,它可能是标准字符集之一,也可能不是。默认字符集在虚拟机启动期间确定,通常取决于基础操作系统使用的区域设置和字符集

然后在另一节的同一链接中,它说

Java编程语言的本机字符编码是UTF-16

我发现很难理解这种明显矛盾的说法,因为:

  • 有人说它依赖于操作系统
  • 另一个(我推断)说,不管操作系统是什么,UTF-16都是Java的字符集(这也是我上面提到的所有链接所说的)
同样,现在,当我执行以下代码时:

package org.sheel.classes;

import java.nio.charset.Charset;

public class Test {

    public static void main(String[] args) {
         System.out.println(Charset.defaultCharset());
    }

}
…在一个在线编辑器中,我可以看到UTF-8。在我的本地系统中,我可以看到windows-1252

最后,还有一个JDK增强方案(),它讨论将默认值更改为UTF-8


这种混淆有什么解释吗?

一个字符串内部是一个字符数组,
tocharray()
,每个字符都是一个utf-16码点。当您将字符串转换为字节数组而不指定字符集时,
getBytes()
,将使用OS one


PS:正如VGR所指出的,最近的实现可能不会将字符串存储为字符数组,但作为程序员,我们通常使用始终为UTF-16的字符进行交互。

字符串使用的内部编码与平台的默认字符集无关。它们彼此完全独立

管柱内部构件 在内部,字符串可以将其数据存储为任何内容。作为程序员,我们不与私有实现交互;我们只能使用公共方法。公共方法通常以UTF-16(
char
value)的形式返回字符串数据,尽管有些方法(如)可以返回完整的UTF-32 int值。这些方法都没有指明字符串数据是如何在内部存储的,只有程序员可以检查这些数据的形式

因此,与其说字符串以UTF-16或任何其他编码的形式在内部存储数据,不如说字符串存储一系列Unicode代码点,并使它们以各种形式可用,最常见的形式是字符值

默认字符集 默认字符集是Java从底层系统获得的东西

正如roberto指出的,当您使用某些(过时的)方法和构造函数时,默认字符集很重要。将字符串转换为字节,或将字节转换为字符串,而不显式指定字符集,将使用默认字符集。类似地,在不指定字符集的情况下创建InputStreamReader或OutputStreamWriter将使用默认字符集

依赖默认字符集通常是不明智的,因为它会使代码在不同的平台上表现出不同的行为。此外,有些字符集可以表示所有已知字符,但有些字符集只能表示整个Unicode指令集的一小部分。特别是,Windows通常有一个默认字符集,它使用一个字节来表示每个字符(
Windows-1252
,在美国版本的Windows中),显然这对于成千上万的可用字符来说是不够的

如果依赖默认字符集,则确实有可能丢失信息:

String s = "\u03c0\u22603"; // "π≠3"

byte[] bytes = s.getBytes();

for (byte b : bytes) {
    System.out.printf("%02x ", b);
}
System.out.println();
在大多数系统上,这将打印:

cf 80 e2 89 a0 33
在Windows上,这可能会打印:

3f 3f 33
pi和不相等字符不在windows-1252字符集中表示,因此在windows上,getBytes方法将它们替换为问号(字节值3f)


如果不涉及字节之间的转换,字符串对象将永远不会丢失信息,因为无论它们如何在内部存储数据,字符串类都保证保留每个字符。

我认为第二部分是指
.java
文件的编码,不是
String
s的字符集。我希望从答案中可以清楚地看出,用户的默认字符编码在本世纪几乎不相关。那么这是否意味着,如果操作系统字符集是UTF-8,并且我的代码中有一个字符串s=“hi there”,那么这个字符串就存储在UTF-16和s.getBytes()中如果不指定字符集,将按照utf-8编码获取字节?如果是,这是否也意味着如果使用这些字节数组构造另一个字符串,它将给您一个可能不同的字符串值?@SheelPancholi yes。(最新版本的Java可能会使用UTF-16以外的东西在内部存储字符串,但这并不重要,因为程序不可能知道它。
char
始终是UTF-16值,不管字符串在内部做什么。)是的,它是。但是,如果你的应用程序要在多个操作系统或多个语言/国家/地区运行,请始终指定一个字符集以避免转换错误。根据JEP,UTF-8是一个不错的选择。@VGR您能详细说明一下吗?说“一个字符总是一个UTF-16值,不管字符串在内部做什么”,听起来像是一个递归矛盾的句子。字符是一个UTF-16值。我同意。但是,当我们说Java中的字符在内部存储时,这不正是我们的意思吗?那怎么可能是“不考虑”?重复我的问题,当使用操作系统字符集(例如utf-8)将这样一个“内部存储的utf-16字符串”转换为它的字节数组时,我们从这样一个字节数组构造一个字符串时,是否会冒得到不同字符串的风险?@Sheel