19

来自 java.lang.StringCoding :

String csn = (charsetName == null) ? "ISO-8859-1" : charsetName;

这是从 Java.lang.getBytes() 使用的,在 linux jdk 7 中我一直认为 UTF-8 是默认字符集?

谢谢

4

4 回答 4

39

这有点复杂......

Java尝试使用默认字符编码来使用 String.getBytes() 返回字节。

  • 默认字符集由系统 file.encoding 属性提供。
  • 这是缓存的,在 JVM 启动后通过 System.setProperty(..) 更改它是没有用的。
  • 如果 file.encoding 属性未映射到已知字符集,则指定 UTF-8。

....这是棘手的部分(可能永远不会发挥作用)....

如果系统无法使用默认字符集(UTF-8 或其他字符集)对字符串进行解码或编码,则会回退到 ISO-8859-1。如果回退不起作用......系统将失败!

.... 真的...(喘气!)...如果我指定的字符集无法使用,并且 UTF-8 或 ISO-8859-1 也无法使用,它会崩溃吗?

是的。StringCoding.encode(...) 方法中的 Java 源代码注释状态:

// 如果我们找不到 ISO-8859-1(必需的编码),那么安装就会出现严重错误。

...然后它调用 System.exit(1)


那么,为什么在 getBytes() 方法中有意回退到 ISO-8859-1 呢?

尽管可能性不大,但用户 JVM 可能不支持 UTF-8 或 JVM 启动时指定的字符集的解码和编码。

那么,getBytes() 期间 String 类中是否正确使用了默认字符集?

不。但是,更好的问题是......


String.getBytes() 是否兑现了它的承诺?

Javadoc 中定义的合同是正确的。

当此字符串无法以默认字符集编码时,此方法的行为未指定。当CharsetEncoder需要对编码过程进行更多控制时,应使用该类。


好消息(以及更好的做事方式)

始终建议在将字节转换为字符串时明确指定“ISO-8859-1”或“US-ASCII”或“UTF-8”或您想要的任何字符集,反之亦然——除非——您之前已经获得默认字符集并 100% 确定它是您需要的字符集。

请改用此方法:

public byte[] getBytes(String charsetName)

要查找系统的默认值,只需使用:

Charset.defaultCharset()

希望有帮助。

于 2012-09-30T07:22:49.237 回答
13

默认情况下,无参数String.getBytes()方法使用 ISO-8859-1。如果可以确定,它将使用默认平台编码。但是,如果它丢失或者是无法识别的编码,它会回退到 ISO-8859-1 作为“默认默认值”。

在实践中你应该很少看到这一点。通常会正确检测到平台默认编码。

但是,我强烈建议您在每次执行编码或解码操作时指定显式字符编码。即使您想要平台默认值,也要明确指定。

于 2012-09-30T07:40:41.327 回答
5

这是出于兼容性的原因。

从历史上看,Windows 和 Unix 上所有未指定字符集的 java 方法当时都使用通用的,即"ISO-8859-1".

正如 Isaac 和 javadoc 所提到的,使用了默认的平台编码(参见Charset.java):

594    public static Charset defaultCharset() {
595        if (defaultCharset == null) {
596            synchronized (Charset.class) {
597                String csn = AccessController.doPrivileged(
598                    new GetPropertyAction("file.encoding"));
599                Charset cs = lookup(csn);
600                if (cs != null)
601                    defaultCharset = cs;
602                else
603                    defaultCharset = forName("UTF-8");
604            }
605        }
606        return defaultCharset;
607    }

在进行字符串到字节或字节到字符串的转换时,始终指定字符集。

即使在这种情况下,String.getBytes()您仍然会发现一个不推荐使用的方法不采用字符集(其中大多数在 Java 1.1 出现时已被弃用)。就像字节顺序一样,平台格式无关紧要,重要的是存储格式的规范。

于 2012-09-30T07:16:34.717 回答
2

详细说明 Skeet 的答案(这当然是正确的)

java.lang.String的源getBytes()调用StringCoding.encode(char[] ca, int off, int len)中,第一行有:

String csn = Charset.defaultCharset().name();

然后(不是立即但绝对)它调用static byte[] StringEncoder.encode(String charsetName, char[] ca, int off, int len)您引用的行的来源 - 作为 charsetName 传递 csn - 所以在这一行中,如果存在,charsetName 它将是默认字符集。

于 2013-04-05T19:37:56.537 回答