6

以下のバイトデータが異なって表示されることを本当に期待していますが、実際には同じです。wiki http://en.wikipedia.org/wiki/UTF-8#Examplesによると、バイト単位のエンコーディングは異なって見えますが、なぜ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]);
    }
4

4 に答える 4

9

Javaは文字をUTF-16として内部的に保持しますが、を使用してバイトに変換すると、各文字はデフォルトのプラットフォームエンコーディングを使用して変換されます。これはおそらくwindows-1252のString.getBytes()ようなものです。私が得ている結果は次のとおりです。

utf16 = -30
utf16 = -126
utf16 = -84
utf8 = -30
utf8 = -126
utf8 = -84

これは、私のシステムではデフォルトのエンコーディングが「UTF-8」であることを示しています。

String.getBytes()のドキュメントには次のコメントがあることにも注意してください。The behavior of this method when this string cannot be encoded in the default charset is unspecified.

ただし、一般的に、次のように常にエンコーディングを指定すると、混乱を避けることができます。a.getBytes("UTF-8")

また、混乱を引き起こす可能性のあるもう1つのことは、ソースファイルに直接Unicode文字を含めることですString a = "€";。そのユーロ記号は、ファイルに1バイト以上保存するためにエンコードする必要があります。Javaがプログラムをコンパイルすると、それらのバイトが認識され、ユーロ記号にデコードされます。あなたは希望する。ユーロ記号をファイルに保存するソフトウェア(メモ帳、日食など)が、Javaが読み戻すときに期待するのと同じ方法でエンコードすることを確認する必要があります。UTF-8の人気は高まっていますが、普遍的ではありません。また、多くのエディターはUTF-8でファイルを書き込みません。

于 2012-10-18T03:00:08.530 に答える
4

1 つの好奇心として、JVM が元のデフォルトの文字セットをどのように知っているのだろうか...

初期のデフォルト文字セットを決定するために JVM が使用するメカニズムは、プラットフォーム固有です。UNIX / UNIX 系システムでは、LANG および LC_* 環境変数によって決定されます。を参照してくださいman locale


えっと..このコマンドは、特定の OS のデフォルトの文字セットを確認するために使用されます。

それは正しいです。しかし、マニュアル エントリには、デフォルトのエンコーディングが環境変数によってどのように決定されるかが記述されているため、そのことについて説明しました。

振り返ってみると、これは元のコメントの意図とは異なる場合がありますが、これがプラットフォームのデフォルトのエンコーディングの指定方法です。(また、個々のファイルの「デフォルト文字セット」の概念は無意味です。以下を参照してください。)

10 個の Java ソース ファイルがあり、その半分が UTF-8 として保存され、残りが UTF-16 として保存されているとします。コンパイル後、それら (クラス ファイル) を別の OS プラットフォームに移動します。 ? デフォルトの文字セット情報は Java クラス ファイルに含まれますか?

これはかなり混乱した一連の質問です。

  1. テキスト ファイルには既定の文字セットがありません。文字セット/エンコーディングがあります。

  2. 非テキスト ファイルには文字エンコーディングがまったくありません。概念は無意味です。

  3. テキスト ファイルの文字エンコーディングを判断する 100% 信頼できる方法はありません。

  4. ファイルのエンコーディングを Java コンパイラに伝えないと、それがプラットフォームのデフォルトのエンコーディングであると見なされます。コンパイラは、あなたを推測しようとしません。エンコーディングが正しくない場合、コンパイラは間違いに気付く場合と気付かない場合があります。

  5. バイトコード (".class") ファイルはバイナリ ファイルです (2 を参照)。

  6. 文字リテラルと文字列リテラルが「.class」ファイルにコンパイルされると、プラットフォームのデフォルトのエンコーディングやその他の影響を受けない方法で表現されるようになりました。

  7. コンパイル時にソース ファイルのエンコーディングを間違えた場合、「.class」ファイル レベルで修正することはできません。唯一の選択肢は、戻ってクラスを再コンパイルし、Java コンパイラに正しいソース ファイルのエンコーディングを伝えることです。

  8. 「10 個の Java ソース ファイルがあり、その半分が UTF-8 で保存され、残りが UTF-16 で保存されているとします。」 .
    ただそれをしないでください!

    • エンコーディングが混在するソース ファイルを保存しないでください。あなたは自分自身を狂わせるでしょう。
    • ファイルをUTF-16で保存する正当な理由はまったくありません...

それで、人々は「プラットフォームに依存する」と言っていますが、それはソースファイルに関連しているのでしょうか?

プラットフォーム依存とは、オペレーティング システム、JVM のベンダーとバージョン、ハードウェアなどに依存する可能性があることを意味します。

ソースファイルとは必ずしも関係ありません。(特定のソース ファイルのエンコーディングは、既定の文字エンコーディングとは異なる場合があります。)

そうでない場合、上記の現象をどのように説明できますか? とにかく、上記の混乱は私の質問を「クラスファイルにエンコード情報が含まれていない可能性があるため、ソースファイルをクラスファイルにコンパイルした後にどうなるか」に拡張され、結果は「プラットフォーム」に依存しますが、ソースファイルには依存しなくなりました?」

プラットフォーム固有のメカニズム (環境変数など) によって、Java コンパイラがデフォルトの文字セットと見なすものが決まります。これをオーバーライドしない限り (たとえば、コマンド ラインで Java コンパイラにオプションを指定するなど)、Java コンパイラはそれをソース ファイルの文字セットとして使用します。ただし、これはソース ファイルの正しい文字エンコーディングではない可能性があります。たとえば、異なるデフォルト文字セットを持つ別のマシンでそれらを作成した場合。また、Java コンパイラが間違った文字セットを使用してソース ファイルをデコードすると、「.class」ファイルに間違った文字コードが挿入される可能性があります。

「.class」ファイルはプラットフォームに依存しません。しかし、ソース ファイルの正しいエンコーディングを Java コンパイラに伝えなかったために、それらが正しく作成されなかった場合、".class" ファイルには間違った文字が含まれます。


「個々のファイルの「デフォルトの文字セット」の概念は無意味です」というのはなぜですか?

本当だから言います!

デフォルトの文字セットとは、指定しない場合に使用される文字セットを意味します。

しかし、テキスト ファイルを正しく保存する方法を制御できますか? メモ帳を使用しても、エンコーディングを選択するオプションがあります。

それは正しいです。これで、ファイルに使用する文字セットをメモ帳に伝えることができます。TELL を指定しない場合、メモ帳はデフォルトの文字セットを使用してファイルを書き込みます。

メモ帳には、テキスト ファイルを読み取るときに文字エンコーディングが何であるかを推測するための黒魔術が少しあります。基本的に、ファイルの最初の数バイトを調べて、UTF-16 バイト オーダー マークで始まるかどうかを確認します。検出された場合、UTF-16、UTF-8 (Microscoft 製品によって生成されたもの)、および「その他」をヒューリスティックに区別できます。しかし、異なる「その他の」文字エンコーディングを区別することはできず、BOM マーカーで始まらないファイルを UTF-8 として認識しません。(UTF-8 ファイルの BOM は Microsoft 固有の規約です ... Java アプリケーションがファイルを読み取り、BOM 文字をスキップすることを認識していない場合、問題が発生します。)

とにかく、問題はソースファイルを書くことではありません。これらは、Java コンパイラーが不適切な文字エンコーディングでソース ファイルを読み取るときに発生します。

于 2012-10-18T03:39:25.897 に答える
3

あなたは悪い仮説に取り組んでいます。メソッドはgetBytes()UTF-16 エンコーディングを使用しません。プラットフォームのデフォルトのエンコーディングを使用します。

メソッドで照会できますjava.nio.charset.Charset.defaultCharset()。私の場合、それは UTF-8 であり、あなたにとっても同じはずです。

于 2012-10-18T03:03:49.230 に答える
1

デフォルトは、UTF-8またはISO-8859-1プラットフォーム固有のエンコーディングが見つからない場合です。ありませんUTF-16。したがって、最終的にはバイト変換UTF-8のみを実行します。だからあなたのbyte[]マッチはあなたが使用してデフォルトのエンコーディングを見つけることができます

 System.out.println(Charset.defaultCharset().name());
于 2012-10-18T03:00:34.053 に答える