Der folgende Code erzeugt die Ausgabe "Hello World!" (Nein wirklich, versuchen Sie es).
public static void main(String... args) {
// The comment below is not a typo.
// \u000d System.out.println("Hello World!");
}
Der Grund dafür ist, dass der Java-Compiler das Unicode-Zeichen \u000d
als neue Zeile analysiert und in Folgendes umwandelt:
public static void main(String... args) {
// The comment below is not a typo.
//
System.out.println("Hello World!");
}
Dies führt dazu, dass ein Kommentar "ausgeführt" wird.
Da dies verwendet werden kann, um bösartigen Code oder was auch immer ein böser Programmierer sich vorstellen kann, zu "verbergen", warum ist dies in Kommentaren erlaubt ?
Warum ist dies in der Java-Spezifikation zulässig?
Antworten:
Die Unicode-Decodierung erfolgt vor jeder anderen lexikalischen Übersetzung. Der Hauptvorteil davon ist, dass es trivial ist, zwischen ASCII und jeder anderen Codierung hin und her zu wechseln. Sie müssen nicht einmal herausfinden, wo Kommentare beginnen und enden!
Wie in JLS Abschnitt 3.3 angegeben, kann jedes ASCII-basierte Tool die Quelldateien verarbeiten:
Dies bietet eine grundlegende Garantie für die Plattformunabhängigkeit (Unabhängigkeit von unterstützten Zeichensätzen), die für die Java-Plattform immer ein zentrales Ziel war.
Die Möglichkeit, ein beliebiges Unicode-Zeichen an einer beliebigen Stelle in der Datei zu schreiben, ist eine nette Funktion und besonders wichtig in Kommentaren, wenn Code in nicht-lateinischen Sprachen dokumentiert wird. Die Tatsache, dass es die Semantik auf solch subtile Weise stören kann, ist nur ein (unglücklicher) Nebeneffekt.
Es gibt viele Fallstricke zu diesem Thema und Java Puzzlers von Joshua Bloch und Neal Gafter enthielten die folgende Variante:
(Dieses Programm stellt sich als einfaches "Hello World" -Programm heraus.)
In der Lösung für das Rätsel weisen sie auf Folgendes hin:
Quelle: Java: Code in Kommentaren ausführen?!
quelle
\u000d
und der Teil danach mit Code-Hervorhebungen enden .// C:\user\...
was zu einem Kompilierungsfehler führt, da\user
es sich nicht um eine gültige Unicode-Escape-Sequenz handelt.\u000d
teilweise hervorgehoben. Nach dem Drücken von Strg + Umschalt + F wird das Zeichen durch eine neue Zeile ersetzt und der Rest der Zeile wird umbrochen\u002A/
sollte den Kommentar beenden.Da dies noch nicht angesprochen wurde, hier eine Erklärung, warum die Übersetzung von Unicode-Escapezeichen vor jeder anderen Quellcode-Verarbeitung erfolgt:
Die Idee dahinter war, dass es verlustfreie Übersetzungen von Java-Quellcode zwischen verschiedenen Zeichencodierungen ermöglicht. Heutzutage gibt es eine weit verbreitete Unicode-Unterstützung, und dies scheint kein Problem zu sein, aber damals war es für einen Entwickler aus einem westlichen Land nicht einfach, einen Quellcode von seinem asiatischen Kollegen mit asiatischen Zeichen zu erhalten. Nehmen Sie einige Änderungen vor ( einschließlich Kompilieren und Testen) und Zurücksenden des Ergebnisses, ohne etwas zu beschädigen.
Java-Quellcode kann also in jeder beliebigen Codierung geschrieben werden und ermöglicht eine Vielzahl von Zeichen innerhalb von Bezeichnern, Zeichen,
String
Literalen und Kommentaren. Um es verlustfrei zu übertragen, werden dann alle Zeichen, die von der Zielcodierung nicht unterstützt werden, durch ihre Unicode-Escapezeichen ersetzt.Dies ist ein reversibler Prozess, und der interessante Punkt ist, dass die Übersetzung von einem Tool durchgeführt werden kann, das nichts über die Java-Quellcodesyntax wissen muss, da die Übersetzungsregel nicht davon abhängig ist. Dies funktioniert, da die Übersetzung in ihre tatsächlichen Unicode-Zeichen im Compiler auch unabhängig von der Java-Quellcodesyntax erfolgt. Dies bedeutet, dass Sie eine beliebige Anzahl von Übersetzungsschritten in beide Richtungen ausführen können, ohne jemals die Bedeutung des Quellcodes zu ändern.
Dies ist der Grund für eine weitere seltsame Funktion, die noch nicht einmal erwähnt wurde: die
\uuuuuuxxxx
Syntax:Wenn ein Übersetzungs - Tool Zeichen und trifft auf eine Sequenz zu entkommen , die bereits eine entkam Sequenz, sollte es eine zusätzliche Einfügen
u
in die Sequenz, die Umwandlung\ucafe
zu\uucafe
. Die Bedeutung ändert sich nicht, aber beim Konvertieren in die andere Richtung sollte das Tool nur eine entfernenu
und nur Sequenzen, die eine einzelne enthalten,u
durch ihre Unicode-Zeichen ersetzen . Auf diese Weise bleiben auch Unicode-Escapezeichen beim Hin- und Herkonvertieren in ihrer ursprünglichen Form erhalten. Ich denke, niemand hat diese Funktion jemals benutzt ...quelle
native2ascii
scheint die\uu...xxxx
Syntax nicht zu verwenden ,native2ascii
sollte helfen, Ressourcenpakete vorzubereiten, indem sie in Iso-Latin-1 konvertiert wurden, da diesProperties.load
so festgelegt wurde, dass nur Latin-1 gelesen wird. Und dort sind die Regeln unterschiedlich, keine\uuu…
Syntax und keine frühe Verarbeitungsphase. In Eigenschaftendateienproperty=multi\u000aline
ist in der Tat das gleiche wieproperty=multi\nline
. (Im Widerspruch zum Satz „Verwenden von Unicode-Escapezeichen wie in Abschnitt 3.3 der Java ™ -Sprachspezifikation definiert“ der Dokumentation)\u
Am einfachsten wäre es gewesen, Escapezeichen zu verbieten , um Zeichen im Bereich U + 0000–007F zu generieren. (Alle diese Zeichen können nativ durch alle nationalen Kodierungen dargestellt werden, die in den 1990er Jahren relevant warenIch werde den Punkt völlig ineffektiv hinzufügen, nur weil ich mir nicht helfen kann und ich noch nicht gesehen habe, dass die Frage ungültig ist, da sie eine versteckte Prämisse enthält, die falsch ist, nämlich dass der Code drin ist ein Kommentar!
Im Java-Quellcode entspricht \ u000d in jeder Hinsicht einem ASCII-CR-Zeichen. Es ist ein Zeilenende, schlicht und einfach, wo immer es auftritt. Die Formatierung in der Frage ist irreführend. Diese Zeichenfolge entspricht tatsächlich syntaktisch:
IMHO ist die richtigste Antwort daher: Der Code wird ausgeführt, weil er nicht in einem Kommentar enthalten ist. Es ist in der nächsten Zeile. "Ausführen von Code in Kommentaren" ist in Java nicht zulässig, wie Sie es erwarten würden.
Ein Großteil der Verwirrung rührt von der Tatsache her, dass Syntax-Textmarker und IDEs nicht hoch genug sind, um diese Situation zu berücksichtigen. Entweder verarbeiten sie die Unicode-Escape-Zeichen überhaupt nicht oder sie tun dies, nachdem sie den Code analysiert haben, anstatt wie zuvor
javac
.quelle
Das
\u000d
Escape beendet einen Kommentar, da\u
Escapezeichen vor dem Tokenisieren des Programms einheitlich in die entsprechenden Unicode-Zeichen konvertiert werden . Sie können auch\u0057\u0057
anstelle von verwenden//
, um einen Kommentar zu beginnen .Dies ist ein Fehler in Ihrer IDE, der die Zeile syntaktisch hervorheben sollte, um zu verdeutlichen, dass
\u000d
der Kommentar endet.Dies ist auch ein Designfehler in der Sprache. Es kann jetzt nicht korrigiert werden, da dies Programme beschädigen würde, die davon abhängen.
\u
Escapezeichen sollten vom Compiler entweder nur in Kontexten in das entsprechende Unicode-Zeichen konvertiert werden, in denen dies "sinnvoll" ist (Zeichenfolgenliterale und -bezeichner und wahrscheinlich nirgendwo anders), oder es sollte ihnen verboten sein, Zeichen im Bereich U + 0000–007F zu generieren , oder beides. Entweder diese Semantik hätte den Kommentar verhindert durch die beendet wird ,\u000d
Flucht, ohne sie mit den Fällen zu stören , wo\u
entkommt nützlich Note sind , dass das beinhaltet die Verwendung von\u
Fluchten im Inneren Kommentar als eine Möglichkeit , zu kodieren Kommentaren in einer nicht-lateinischen Schrift, weil die Der Texteditor könnte einen breiteren Blick darauf werfen, wo\u
Escapezeichen sind bedeutender als der Compiler. (Mir ist jedoch kein Editor oder keine IDE bekannt, die\u
Escapezeichen in einem beliebigen Kontext als entsprechende Zeichen anzeigen .)Es gibt einen ähnlichen Entwurfsfehler in der C-Familie 1, bei dem Backslash-Newline verarbeitet wird, bevor Kommentargrenzen bestimmt werden, z
Ich erwähne dies, um zu veranschaulichen, dass es einfach ist, diesen bestimmten Entwurfsfehler zu machen, und erst dann zu erkennen, dass es sich um einen Fehler handelt, wenn es zu spät ist, ihn zu korrigieren, wenn Sie es gewohnt sind, über Tokenisierung nachzudenken und die Denkweise von Compiler-Programmierern zu analysieren über Tokenisierung und Analyse. Wenn Sie Ihre formale Grammatik bereits definiert haben und dann jemand einen syntaktischen Sonderfall entwickelt - Trigraphen, Backslash-Newline, Codierung beliebiger Unicode-Zeichen in Quelldateien, die auf ASCII beschränkt sind, was auch immer -, die eingeklemmt werden müssen, ist dies einfacher Fügen Sie vor dem Tokenizer einen Transformationsdurchlauf hinzu, um den Tokenizer neu zu definieren und darauf zu achten, wo es sinnvoll ist, diesen Sonderfall zu verwenden.
1 Für Pedanten: Mir ist bewusst, dass dieser Aspekt von C zu 100% beabsichtigt war, mit der Begründung - ich denke mir das nicht aus -, dass Sie damit Code mit beliebig langen Zeilen mechanisch auf Lochkarten anpassen können. Es war immer noch eine falsche Designentscheidung.
quelle
\u
weniger absurd war als die Entscheidung, Cs Führung bei der Verwendung führender Nullen für die Oktalnotation zu folgen. Obwohl die Oktalschreibweise manchmal nützlich ist, habe ich noch niemanden gehört, der ein Argument formuliert, warum eine führende Null eine gute Möglichkeit ist, dies anzuzeigen.\u
als Transformation vor der Tokenisierung, wenn es verboten wäre, Zeichen im Bereich U + 0000..U + 007F zu erzeugen. Es ist die Kombination aus "das funktioniert überall" und "dies aliasisiert ASCII-Zeichen mit syntaktischer Bedeutung", die es von umständlich zu völlig falsch herabsetzt.//
einzeiligen Kommentar nicht . Und da C eine Erklärung Terminator hat , die nicht eine neue Linie ist, wäre es vor allem für lange Strings verwendet werden, mit der Ausnahme , dass so weit wie ich „Stringliteral Verkettung“ bestimmen kann , war es von K & R.Dies war eine absichtliche Designentscheidung, die bis zum ursprünglichen Design von Java zurückreicht.
Für diejenigen, die fragen: "Wer möchte, dass Unicode in Kommentaren entkommt?", Sind sie vermutlich Leute, deren Muttersprache den lateinischen Zeichensatz verwendet. Mit anderen Worten, es ist dem ursprünglichen Design von Java inhärent, dass Leute beliebige Unicode-Zeichen verwenden können, wo immer dies in einem Java-Programm zulässig ist, am typischsten in Kommentaren und Zeichenfolgen.
Es ist wohl ein Mangel in Programmen (wie IDEs), die zum Anzeigen des Quelltextes verwendet werden, dass solche Programme die Unicode-Escapezeichen nicht interpretieren und die entsprechende Glyphe anzeigen können.
quelle
Ich stimme @zwol zu, dass dies ein Designfehler ist. aber ich bin noch kritischer.
\u
Escape ist in String- und Char-Literalen nützlich. und das ist der einzige Ort, an dem es existieren sollte. Es sollte genauso gehandhabt werden wie andere Fluchten wie\n
; und"\u000A"
sollte genau bedeuten"\n"
.Es hat absolut keinen Sinn,
\uxxxx
Kommentare zu haben - das kann niemand lesen.Ebenso macht es keinen Sinn,
\uxxxx
in einem anderen Teil des Programms zu verwenden. Die einzige Ausnahme besteht wahrscheinlich in öffentlichen APIs, die gezwungen sind, einige Nicht-ASCII-Zeichen zu enthalten - was haben wir das letzte Mal gesehen?Die Designer hatten ihre Gründe im Jahr 1995, aber 20 Jahre später scheint dies eine falsche Wahl zu sein.
(Frage an die Leser - warum erhält diese Frage immer wieder neue Stimmen? Ist diese Frage von einem beliebten Ort aus verknüpft?)
quelle
int \u5431
wenn Sie könnenint 整
UTF-8
Unterstützung). Sie müssen nur eine Methode aufrufen und möchten nicht das Support Pack für die asiatische Sprache Ihres Betriebssystems (denken Sie daran, die neunziger Jahre) für diese einzelne Methode installieren…Die einzigen Personen, die antworten können, warum Unicode-Escapezeichen so implementiert wurden, wie sie waren, sind die Personen, die die Spezifikation geschrieben haben.
Ein plausibler Grund dafür ist, dass der Wunsch bestand, das gesamte BMP als mögliche Zeichen des Java-Quellcodes zuzulassen. Dies stellt jedoch ein Problem dar:
Dies ist unglaublich schwierig, wenn Unicode-Fluchten in den Kampf ziehen: Es werden eine ganze Menge neuer Lexer-Regeln erstellt.
Der einfache Ausweg besteht darin, das Lexen in zwei Schritten durchzuführen: Suchen und ersetzen Sie zuerst alle Unicode-Escapezeichen durch das Zeichen, das sie darstellen, und analysieren Sie dann das resultierende Dokument, als ob Unicode-Escapezeichen nicht vorhanden wären.
Das Beste daran ist, dass es einfach zu spezifizieren ist, wodurch die Spezifikation einfacher und einfacher zu implementieren ist.
Der Nachteil ist Ihr Beispiel.
quelle