Java中的UTF-8和UTF-16

Java中的UTF-8和UTF-16,java,string,encoding,utf-8,Java,String,Encoding,Utf 8,我真的希望下面的字节数据应该显示不同,但事实上,它们是相同的,根据wiki的说法,字节中的编码看起来不同,但是为什么Java会将它们打印出来呢 String a = "€"; byte[] utf16 = a.getBytes(); //Java default UTF-16 byte[] utf8 = null; try { utf8 = a.getBytes("UTF-8"); } catch (UnsupportedEncoding

我真的希望下面的字节数据应该显示不同,但事实上,它们是相同的,根据wiki的说法,字节中的编码看起来不同,但是为什么Java会将它们打印出来呢

    String a = "€";
    byte[] utf16 = a.getBytes(); //Java default UTF-16
    byte[] utf8 = null;

    try {
        utf8 = a.getBytes("UTF-8");
    } catch (UnsupportedEncodingException e) {
        throw new RuntimeException(e);
    }

    for (int i = 0 ; i < utf16.length ; i ++){
        System.out.println("utf16 = " + utf16[i]);
    }

    for (int i = 0 ; i < utf8.length ; i ++){
        System.out.println("utf8 = " + utf8[i]);
    }
字符串a=“€”;
字节[]utf16=a.getBytes()//Java默认UTF-16
字节[]utf8=null;
试一试{
utf8=a.getBytes(“UTF-8”);
}捕获(不支持的编码异常e){
抛出新的运行时异常(e);
}
对于(int i=0;i
尽管Java内部将字符保存为UTF-16,但当您使用
String.getBytes()
转换为字节时,每个字符都会使用默认的平台编码进行转换,这可能类似于。我得到的结果是:

utf16 = -30
utf16 = -126
utf16 = -84
utf8 = -30
utf8 = -126
utf8 = -84
这表明在我的系统上默认编码为“UTF-8”

另外请注意,String.getBytes()的文档中有这样一条注释:
当无法在默认字符集中对该字符串进行编码时,该方法的行为未指定。

不过,一般来说,如果您总是像使用
a.getBytes(“UTF-8”)


另外,另一件可能导致混淆的事情是在源文件中直接包含Unicode字符:
String a=“€”。必须对该欧元符号进行编码,以将其存储为文件中的一个或多个字节。当Java编译程序时,它会看到这些字节并将它们解码回欧元符号。希望如此。您必须确保将欧元符号保存到文件中的软件(记事本、eclipse等)的编码方式与Java读回欧元符号时的编码方式相同。UTF-8正变得越来越流行,但它不是通用的,许多编辑器不会用UTF-8编写文件。

如果找不到特定于平台的编码,则默认为
UTF-8
ISO-8859-1
。非
UTF-16
。因此,最终您只能在
UTF-8
中进行字节转换。 这就是您的
字节[]
匹配的原因 您可以使用

 System.out.println(Charset.defaultCharset().name());

你的假设是错误的。
getBytes()
方法不使用UTF-16编码。它使用平台默认编码

您可以使用
java.nio.charset.charset.defaultCharset()方法查询它。在我的情况下,它是UTF-8,你也应该是一样的

好奇的是,我想知道JVM是如何知道原始默认字符集的

JVM用于确定初始默认字符集的机制是特定于平台的。在类UNIX/UNIX系统上,它由LANG和LC_*环境变量决定;请参见
人工语言环境



嗯。。此命令用于检查特定操作系统中的默认字符集是什么

这是正确的。但是我告诉过你,因为手动输入描述了默认编码是如何由环境变量决定的

回想起来,这可能不是您最初评论的意思,但这是指定平台默认编码的方式。(单个文件的“默认字符集”概念毫无意义;见下文。)

假设我有10个Java源文件,其中一半保存为UTF-8,其余保存为UTF-16,在编译后,我将它们(类文件)移动到另一个操作系统平台,现在JVM如何知道它们的默认编码?Java类文件中是否包含默认字符集信息

这是一组相当混乱的问题:

  • 文本文件没有默认字符集。它有一个字符集/编码

  • 非文本文件根本没有字符编码。这个概念毫无意义

  • 没有100%可靠的方法来确定文本文件的字符编码是什么

  • 如果您不告诉java编译器文件的编码是什么,它将假定它是平台的默认编码。编译器不会试图猜测你。如果编码不正确,编译器可能会甚至不会注意到您的错误

  • 字节码(“.class”)文件是二进制文件(见2)

  • 当字符和字符串文字被编译成“.class”文件时,它们现在的表示方式不受平台默认编码或任何其他您可以影响的方式的影响

  • 如果编译时源文件编码出错,则无法在“.class”文件级别修复它。您唯一的选择是返回并重新编译类,告诉Java编译器正确的源文件编码

  • “假设我有10个Java源文件,其中一半保存为UTF-8,其余保存为UTF-16会怎么样?” 别这样

    • 不要以混合编码方式保存源文件。你会发疯的
    • 我根本找不到一个好的理由将文件存储在UTF-16中


  • 所以,我很困惑,当人们说“依赖于平台”时,它是否与源文件相关

    平台依赖意味着它可能取决于操作系统、JVM供应商和版本、硬件等

    它不一定与源文件相关。(任何给定源文件的编码可能不同于默认字符编码。)

    如果不是,我如何解释上述现象?总之,上面的混淆将我的问题扩展到“那么,在我将源文件编译成类文件之后会发生什么,因为类文件可能不包含编码信息,所以现在结果实际上依赖于‘平台’,而不再依赖于源文件?”

    特定于平台的机制(例如环境变量)决定了java编译器将什么视为默认字符集。Unl