web-dev-qa-db-ja.com

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がデフォルトの文字セットであるという印象を受けましたか?

ありがとう

18
Amnon

それは少し複雑です...

Java triesデフォルトの文字エンコーディングを使用して、String.getBytes()を使用してバイトを返します。

  • デフォルトの文字セットは、システムのfile.encodingプロパティによって提供されます。
  • これはキャッシュされ、JVMの起動後にSystem.setProperty(..)を使用して変更しても意味がありません。
  • File.encodingプロパティが既知の文字セットにマップされない場合は、UTF-8が指定されています。

....これはトリッキーな部分です(これはおそらく出てくることはないでしょう)....

システムがデフォルトの文字セット(UTF-8または別の文字セット)を使用して文字列をデコードまたはエンコードできない場合、ISO-8859-1へのフォールバックが発生します。フォールバックが機能しない場合...システムは失敗します!

....本当に...(gasp!)...指定した文字セットを使用できず、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()

お役に立てば幸いです。

36
The Coordinator

パラメータなしのString.getBytes()メソッドしない ISO-8859-1をデフォルトで使用します。判別できる場合は、デフォルトのプラットフォームエンコーディングを使用します。ただし、それが欠落しているか、認識されないエンコーディングの場合は、「デフォルトのデフォルト」としてISO-8859-1にフォールバックします。

veryこれは実際にはめったに見られません。通常、プラットフォームのデフォルトのエンコーディングは正しく検出されます。

ただし、エンコードまたはデコード操作を実行するたびに、明示的な文字エンコードを指定することを強くお勧めします。プラットフォームのデフォルトが必要な場合でも、明示的に指定してください。

12
Jon Skeet

これは互換性のためです。

従来、すべてのJava 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が表示された場合、それらのほとんどは非推奨です)。エンディアン、プラットフォーム形式は無関係であり、関連するのはストレージ形式の基準です。

5
Denys Séguret

スキートの答えについて詳しく説明します(もちろん正しい答えです)

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は、存在する場合、デフォルトの文字セットになります

1
Mr_and_Mrs_D