Von der Kompilation zur Laufzeit wie funktioniert die Java-String-Codierung wirklich funktionieren
Ich realisierte, dass ich nicht vollständig verstehen, Java-string-Kodierung.
Betrachten Sie den folgenden code:
public class Main
{
public static void main(String[] args)
{
System.out.println(java.nio.charset.Charset.defaultCharset().name());
System.out.println("ack char: ^"); /* where ^ = 0x06, the ack char */
}
}
Da die control-Zeichen sind anders interpretiert, die zwischen windows-1252 und ISO-8859-1, wählte ich die ack
char zum testen.
Ich jetzt kompilieren Sie es mit unterschiedlichen Dateitypen, Kodierungen, UTF-8, windows-1252, und ISO-8859-1. Die beiden zusammenzustellen, die genau die gleiche Sache, byte-per-byte als verified by md5sum
.
Ich dann das Programm ausführen:
$ java Main | hexdump -C
00000000 55 54 46 2d 38 0a 61 63 6b 20 63 68 61 72 3a 20 |UTF-8.ack char: |
00000010 06 0a |..|
00000012
$ java -Dfile.encoding=iso-8859-1 Main | hexdump -C
00000000 49 53 4f 2d 38 38 35 39 2d 31 0a 61 63 6b 20 63 |ISO-8859-1.ack c|
00000010 68 61 72 3a 20 06 0a |har: ..|
00000017
$ java -Dfile.encoding=windows-1252 Main | hexdump -C
00000000 77 69 6e 64 6f 77 73 2d 31 32 35 32 0a 61 63 6b |windows-1252.ack|
00000010 20 63 68 61 72 3a 20 06 0a | char: ..|
00000019
It-Ausgaben korrekt den 0x06
egal, welche Kodierung verwendet wird.
Ok, es sind noch Ausgänge die gleiche 0x06
, der würde interpretiert werden als der druckbare [ACK] char von windows-codepages 1252.
Führt mich zu ein paar Fragen:
- Ist die codepage /Zeichensatz der Java-Datei kompiliert wird voraussichtlich identisch sein mit dem default-charset des Systems, unter denen es zusammengestellt? Sind die beiden immer gleichbedeutend?
- Die kompilierte Repräsentation scheint nicht abhängig vom compile-Zeit-Zeichensatz, ist dies tatsächlich der Fall ist?
- Bedeutet dies, dass Zeichenfolgen innerhalb von Java-Dateien möglicherweise anders interpretiert zur Laufzeit, wenn Sie nicht verwenden standard-Zeichen für den aktuellen charset/locale?
- Was sollte ich wirklich wissen, über die string-und character-encoding in Java?
- Es ist nicht klar, was du meinst mit "kompilieren Sie es mit anderen Datei-Codierungen". Meinst du, dass Sie speichern Sie die Datei in verschiedenen Kodierungen, kompilieren Sie dann jeweils die Dateien mit dem -Codierung Schalter zu javac? Wenn ja, wie tun Sie wissen, was random Müll ist die Abwicklung in der Quell-Dateien nach dem speichern Sie in diesen Codierungen? Sie können nicht ein literal-Steuerelement Zeichen Sie in Ihre Quelle und erwarten, dass es, um zu überleben-Serialisierung in kodierte Zeichen.
- Eine Datei ist nichts anderes als ein Strom von bytes. Diese bytes werden unterschiedlich interpretiert, abhängig von der Zeichencodierung, Sie sind davon ausgegangen, dass in. So, ich bin auf Saiten, die enthalten
char
s, die möglicherweise unterschiedlich interpretiert werden, entweder zur Laufzeit oder zur Compilezeit, durch die Annahme der Datei kodiert wurde in verschiedenen Zeichen-sets. - Explizit über die Zusammenstellung Schritt, die ich verwendet, Sonne encoding-Eigenschaft legen Sie den Zeichensatz bei der Kompilierung:
javac -encoding windows-1252 Main.java
, die mit der Kodierung entsprechend gesetzt.
Du musst angemeldet sein, um einen Kommentar abzugeben.
javac -encoding...
); ansonsten-Plattform-Codierung wird angenommenSystem.out
PrintStream
verwandeln Sie Ihre strings aus UTF-16-Byte in das system-encoding vor, Sie zu schreiben, um stdoutHinweise:
-Dfile.- encoding
Einer Zusammenfassung "was zu wissen" über die string-Codierungen in Java:
String
Instanz im Speicher ist eine Sequenz von 16-bit - "code units", welche Java-Griffechar
Werte. Konzeptionell ist diese code-Einheiten codieren einer Sequenz von "code points", wo ein code point "die Anzahl zurückzuführen auf ein bestimmtes Zeichen gemäß der Unicode-standard". Code Punkte im Bereich von 0 bis etwas mehr als eine million, obwohl nur 100 tausend oder so definiert wurden, so weit. Code-Punkte von 0 bis 65535 kodiert sind, in einer einzigen code-Einheit, während die anderen code-Punkte verwenden Sie zwei code-Einheiten. Dieser Vorgang wird als UTF-16 (auch bekannt als UCS-2). Es gibt ein paar Feinheiten (einige code-Punkte sind ungültig, z.B. 65535, und es gibt eine Reihe von 2048 Codepunkte im ersten 65536 reserved genau für die Kodierung der andere code Punkte).System.out.println()
die JVM konvertiert den string in etwas passendes für überall dort, wo diese Zeichen gehen, was oft bedeutet die Umwandlung in bytes, die mit einem Zeichensatz, die abhängig von der aktuellen locale (oder das, was die JVM Ahnen von der aktuellen locale).javac
) akzeptiert Kommandozeilen-flag (-encoding
), die verwendet werden kann zum überschreiben des Standard-Wahl.String
Instanzen hängen Sie nicht jeder Art von Codierung, solange Sie im RAM bleiben, einige der Operationen, die Sie durchführen wollen, auf strings locale-abhängig. Dies ist nicht eine Frage der Kodierung, aber ein Gebietsschema definiert auch eine "Sprache", und so kommt es, dass die Begriffe " groß-und Kleinschreibung hängt von der Sprache ab, die verwendet wird. Die Üblichen Verdächtigen ruft"unicode".toUpperCase()
: dies ergibt"UNICODE"
außer wenn das aktuelle Gebietsschema Türkisch, in diesem Fall erhalten Sie"UNİCODE"
(die "I
" hat einen Punkt). Die Grundannahme hier ist, dass, wenn das aktuelle Gebietsschema Türkisch ist, dann werden die Daten der Anwendung ist die Verwaltung von wahrscheinlich türkischen text; ich persönlich finde diese Annahme bestenfalls fragwürdig. Aber so ist es.In der Praxis, sollten Sie Codierungen explizit in Ihrem code, zumindest die meiste Zeit. Rufen Sie nicht
String.getBytes()
rufenString.getBytes("UTF-8")
. Verwendung von Standard -, locale-abhängige Codierung in Ordnung ist, wenn es verwendet wird, um einige Daten ausgetauscht mit dem Benutzer, wie eine Konfigurationsdatei oder eine Meldung anzeigen lassen, sofort, aber an anderer Stelle, vermeiden locale-abhängige Methoden, Wann immer möglich.Unter anderen locale-abhängigen Teile von Java, gibt es Kalender. Es ist die ganze Zeit-zone business, die abhängig von der "time zone", das sollte beziehen sich auf die geografische position des Computers (und dies ist nicht Teil der "locale" stricto sensu...). Auch unzählige Java-Anwendung auf mysteriöse Weise fehl, wenn Sie laufen in Bangkok, weil Sie in einem Thai-Gebietsschema, Java defaults nach dem Buddhistischen Kalender, nach denen das aktuelle Jahr 2553.
Als Faustregel davon ausgehen, dass die Welt ist riesig (es ist !) und die Dinge die generische (nicht tun nichts, die hängt vom Zeichensatz bis zum letzten moment, wenn I/O muss auch tatsächlich durchgeführt werden).
Wenn Sie kompilieren mit unterschiedlichen Kodierungen, die Kodierungen wirken sich nur auf Ihre source-Dateien. Wenn Sie keine speziellen Zeichen innerhalb Ihrer Quellen, wird es keinen Unterschied in den resultierenden byte-code.
Für die Laufzeit der Standard-Zeichensatz des Betriebssystems verwendet. Dies ist unabhängig vom Zeichensatz Sie verwendet zum kompilieren.
Erm basiert auf diese und diese der ACK steuerzeichen ist genau das gleiche in beiden Kodierungen. Der Unterschied der link, den Sie darauf hingewiesen, darüber zu reden, wie DOS/Windows hat eigentlich Symbole für die meisten von den control-Zeichen in Windows-1252 (wie Herz/Club/Spade/Diamant-Zeichen und simileys), während ISO-8859 nicht.