为什么Java的String.getBytes()使用“ISO-8859-1”
来自java.lang.StringCoding:
String csn = (charsetName == null) ? "ISO-8859-1" : charsetName;
这是从Java.lang.getBytes()中使用的,在linux jdk 7中我总是认为UTF-8是默认的字符集?
谢谢
这有点复杂……
Java 尝试使用默认字符编码使用String.getBytes()返回字节。
- 默认字符集由系统file.encoding属性提供。
- 这是缓存的,在JVM启动后通过System.setProperty(..)更改它是没有用的。
- 如果file.encoding属性未映射到已知的字符集,则指定UTF-8。
….这是棘手的部分(可能永远不会发挥作用)….
如果系统无法使用默认字符集(UTF-8或其他字符串)对字符串进行解码或编码,则将回退到ISO-8859-1。 如果后备不起作用……系统将失败!
….真的……(喘气!)……如果我的指定字符集无法使用,UTF-8或ISO-8859-1也无法使用,它会崩溃吗?
是。 String源码注释状态在StringCoding.encode(…)方法中:
//如果我们找不到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()
希望有所帮助。
默认情况下,无参数的String.getBytes()
方法不使用ISO-8859-1。 如果可以确定,它将使用默认平台编码。 但是,如果丢失或者是无法识别的编码,则它将作为“默认默认值”回退到ISO-8859-1。
你应该很少在实践中看到这一点。 通常,将正确检测平台默认编码。
但是,我强烈建议您在每次执行编码或解码操作时指定显式字符编码。 即使您希望平台默认,也请明确指定。
这是出于兼容性的原因。
从历史上看,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()
的情况下,您仍然会发现一个不使用charset的非弃用方法(当Java 1.1出现时,大多数方法都被弃用)。 就像字节序一样,平台格式是无关紧要的,相关的是存储格式的规范。
详细说明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
将是默认字符集(如果存在)。