Это действительно странно ... После установки Charset по умолчанию кэшируется и не изменяется, пока класс находится в памяти. Установка свойства "file.encoding"
с помощью System.setProperty("file.encoding", "Latin-1");
ничего не делает. Каждый раз, когда вызывается Charset.defaultCharset()
, он возвращает кэшированную кодировку.
Вот мои результаты:
Default Charset=ISO-8859-1
file.encoding=Latin-1
Default Charset=ISO-8859-1
Default Charset in Use=ISO8859_1
Я использую JVM 1.6, хотя.
(обновление)
Хорошо. Я воспроизвел вашу ошибку с JVM 1.5.
Глядя на исходный код 1.5, кэшированная кодировка по умолчанию не устанавливается. Я не знаю, является ли это ошибкой или нет, но 1.6 изменяет эту реализацию и использует кэшированный набор символов:
JVM 1.5:
public static Charset defaultCharset() {
synchronized (Charset.class) {
if (defaultCharset == null) {
java.security.PrivilegedAction pa =
new GetPropertyAction("file.encoding");
String csn = (String) AccessController.doPrivileged(pa);
Charset cs = lookup(csn);
if (cs != null)
return cs;
return forName("UTF-8");
}
return defaultCharset;
}
}
JVM 1.6:
public static Charset defaultCharset() {
if (defaultCharset == null) {
synchronized (Charset.class) {
java.security.PrivilegedAction pa =
new GetPropertyAction("file.encoding");
String csn = (String) AccessController.doPrivileged(pa);
Charset cs = lookup(csn);
if (cs != null)
defaultCharset = cs;
else
defaultCharset = forName("UTF-8");
}
}
return defaultCharset;
}
Когда вы устанавливаете кодировку файла на file.encoding=Latin-1
при следующем вызове Charset.defaultCharset()
, происходит следующее: поскольку кэшированная кодировка по умолчанию не установлена, она попытается найти соответствующую кодировку для имени Latin-1
, Это имя не найдено, поскольку оно неверно и возвращает значение по умолчанию UTF-8
.
Что касается того, почему классы ввода-вывода, такие как OutputStreamWriter
, возвращают неожиданный результат,
реализация sun.nio.cs.StreamEncoder
(ведьма используется этими классами ввода-вывода) также отличается для JVM 1.5 и JVM 1.6. Реализация JVM 1.6 основана на методе Charset.defaultCharset()
для получения кодировки по умолчанию, если она не предоставляется классам ввода-вывода. Реализация JVM 1.5 использует другой метод Converters.getDefaultEncodingName();
для получения кодировки по умолчанию. Этот метод использует собственный кэш кодировки по умолчанию, который устанавливается при инициализации JVM:
JVM 1.6:
public static StreamEncoder forOutputStreamWriter(OutputStream out,
Object lock,
String charsetName)
throws UnsupportedEncodingException
{
String csn = charsetName;
if (csn == null)
csn = Charset.defaultCharset().name();
try {
if (Charset.isSupported(csn))
return new StreamEncoder(out, lock, Charset.forName(csn));
} catch (IllegalCharsetNameException x) { }
throw new UnsupportedEncodingException (csn);
}
JVM 1.5:
public static StreamEncoder forOutputStreamWriter(OutputStream out,
Object lock,
String charsetName)
throws UnsupportedEncodingException
{
String csn = charsetName;
if (csn == null)
csn = Converters.getDefaultEncodingName();
if (!Converters.isCached(Converters.CHAR_TO_BYTE, csn)) {
try {
if (Charset.isSupported(csn))
return new CharsetSE(out, lock, Charset.forName(csn));
} catch (IllegalCharsetNameException x) { }
}
return new ConverterSE(out, lock, csn);
}
Но я согласен с комментариями. Вы не должны полагаться на это свойство . Это деталь реализации.