Was sind "Verbindungszeichen" in Java-Bezeichnern?

208

Ich lese für SCJP und habe eine Frage zu dieser Zeile:

Bezeichner müssen mit einem Buchstaben, einem Währungszeichen ($) oder einem Verbindungszeichen wie dem Unterstrich (_) beginnen. Bezeichner können nicht mit einer Nummer beginnen!

Es besagt, dass ein gültiger Bezeichnername mit einem Verbindungszeichen wie einem Unterstrich beginnen kann. Ich dachte, Unterstriche wären die einzig gültige Option? Welche anderen verbindenden Charaktere gibt es?

Lucky Luke
quelle
2
In Bezug auf "ein Währungszeichen": Britische Besucher dieser Frage sind möglicherweise überrascht und interessiert zu wissen, dass Java-Kennungen legal mit dem Pfund-Symbol (£) beginnen können, wenn sie mit "einem" Währungszeichen beginnen können.
8bitjunkie
11
Beachten Sie, dass Java 8 seit "8 _" ein "veralteter" Bezeichner ist. Insbesondere gibt der Compiler die folgende Warnung aus: (Die Verwendung von '_' als Bezeichner wird in Releases nach Java SE 8 möglicherweise nicht unterstützt .)
Aioobe
4
@aioobe Yup. Brian Goetz sagt, dass sie "zurückfordern", _um sie in zukünftigen Sprachfunktionen zu verwenden . Bezeichner, die mit einem Unterstrich beginnen, sind noch in Ordnung, aber ein einzelner Unterstrich ist ein Fehler, wenn er als Lambda-Parametername und überall eine Warnung verwendet wird.
Boann
1
Für den Bytecode gilt alles nach Sequenz, was nicht enthalten ist . ; [ / < > :: stackoverflow.com/questions/26791204/… docs.oracle.com/javase/specs/jvms/se7/html/… Alles andere ist eine reine Java-Einschränkung.
Ciro Santilli 5 冠状 病 六四 事件 5
@Boann Das Lustige ist, dass sie die Verwendung in Lambdas nicht zulassen, aber es wird wahrscheinlich als Kennung "Dieses Argument ignorieren" zurückkommen, die z. B. in Lambdas verwendet wird. Ich habe nur versucht, es so zu verwenden : _, _ -> doSomething();.
user31389

Antworten:

268

Hier ist eine Liste der Verbindungszeichen. Dies sind Zeichen, die zum Verbinden von Wörtern verwendet werden.

http://www.fileformat.info/info/unicode/category/Pc/list.htm

U+005F _ LOW LINE
U+203F  UNDERTIE
U+2040  CHARACTER TIE
U+2054  INVERTED UNDERTIE
U+FE33  PRESENTATION FORM FOR VERTICAL LOW LINE
U+FE34  PRESENTATION FORM FOR VERTICAL WAVY LOW LINE
U+FE4D  DASHED LOW LINE
U+FE4E  CENTRELINE LOW LINE
U+FE4F  WAVY LOW LINE
U+FF3F _ FULLWIDTH LOW LINE

Dies wird unter Java 7 kompiliert.

int _, ‿, ⁀, ⁔, ︳, ︴, ﹍, ﹎, ﹏, _;

Ein Beispiel. In diesem Fall tpist der Name einer Spalte und der Wert für eine bestimmte Zeile.

Column<Double> tp = table.getColumn("tp", double.class);

double tp = row.getDouble(︴tp︴);

Folgende

for (int i = Character.MIN_CODE_POINT; i <= Character.MAX_CODE_POINT; i++)
    if (Character.isJavaIdentifierStart(i) && !Character.isAlphabetic(i))
        System.out.print((char) i + " ");
}

druckt

$ _ ¢ £ ¤ ¥ ¥ ৲ ৳ ৻ ૱ ௹ ฿ ៛ ‿ ⁀ ⁔ ₠ ₡ ₢ ₣ ₤ ₦ ₧ ₨ ₪ ₫ ₭ ₮ ₯ ﹩ $ _ ¢ £ £ ¥

Peter Lawrey
quelle
109
Ich freue mich auf den Tag, an dem ich Code erbe, der diese Bezeichner verwendet!
Marko Topolnik
58
@MarkoTopolnik Sei vorsichtig, was du dir wünschst. ;)
Peter Lawrey
3
Übrigens können Sie auch jedes der Währungssymbole verwenden. int ৲, ¤, ₪₪₪₪;: D
Peter Lawrey
17
Ich könnte ein oder zwei davon in meinen Code werfen, nur zum Spaß! Und um zu testen, ob das Build-System wirklich UTF-8-kompatibel ist.
Marko Topolnik
82
@ AbrahamBorland Wie wäre es mit if( ⁀ ‿ ⁀ == ⁀ ⁔ ⁀) oder if ($ == $)oder if (¢ + ¢== ₡)oderif (B + ︳!= ฿)
Peter Lawrey
25

Durchlaufen Sie die gesamten 65.000 Zeichen und fragen Sie Character.isJavaIdentifierStart(c). Die Antwort lautet: "Undertie" Dezimal 8255

Markus Mikkolainen
quelle
14
Ich konnte nicht widerstehen (in Scala): (1 to 65535).map(_.toChar).filter(Character.isJavaIdentifierStart).size- ergibt 48529 Zeichen ...
Tomasz Nurkiewicz
Es scheint ein paar Charaktere in der Nähe von 65k und 12k und 8,5k usw. zu geben.
Markus Mikkolainen
gibt nicht nach, wenn Sie "! isLetter" und "! isDigit" sagen
Markus Mikkolainen
2546 + 2547 mindestens "Box Drawing ..."
Markus Mikkolainen
3
Gesamtzahl = 90648, aber ich werde Character.MAX_CODE_POINT, was wahrscheinlich mehr als ist 2<<16.
Martijn Courteaux
7

Die endgültige Spezifikation einer legalen Java-Kennung finden Sie in der Java-Sprachspezifikation .

Greg Hewgill
quelle
3
Ich bin mir nicht sicher, ob die (implizite) Frage, welche Zeichen einen Java-Bezeichner starten könnten, tatsächlich vollständig beantwortet ist. Wenn wir den folgenden Links folgen, gelangen wir zu Character.isJavaIdentifierStart (), der besagt, dass ein Zeichen einen Java-Bezeichner genau dann starten kann, wenn eine der folgenden Bedingungen erfüllt ist: ... ch ist ein Währungssymbol ( z. B. "$"); ch ist ein verbindendes Interpunktionszeichen ( z. B. "_").
ein CVn
1
Es scheint, dass die Spezifikation die endgültige Liste der akzeptablen Zeichen bis zur Implementierung überlässt, sodass sie möglicherweise für alle unterschiedlich sein kann.
Greg Hewgill
3
@ GregHewgill Das wäre dumm, wenn man bedenkt, wie genau alles andere spezifiziert ist. Ich denke, dass dies tatsächliche Unicode-Zeichenklassen sind, die (wo sonst?) Im Unicode-Standard definiert sind. isJavaIdentifierStart () erwähnt getType (), und Währungssymbol und Connector-Interpunktion sind ebenfalls Typen, die von dieser Funktion zurückgegeben werden können, sodass die Listen möglicherweise dort angegeben werden. "Allgemeine Kategorie" ist in der Tat ein spezifischer Begriff im Unicode-Standard. So werden die gültigen Werte wären L[alles], Nl, Sc, Pc.
Random832
3
@ GregHewgill ist richtig. Die Spezifikation ist kurz und klar und wird durch Character.isJavaIdentifierStart () und Character.isJavaIdentifierPart () definiert. Das Ende. Das Wichtigste ist, dass sich Unicode weiterentwickelt. Fallen Sie nicht in die Falle, wenn Sie daran denken, dass Zeichensätze fertig sind (Latein ist ein schreckliches Beispiel; ignorieren Sie es). Charaktere werden ständig erstellt. Fragen Sie Ihre japanischen Freunde. Erwarten Sie, dass sich die legalen Java-Kennungen im Laufe der Zeit ändern - und das ist beabsichtigt. Es geht darum, Menschen Code in menschlichen Sprachen schreiben zu lassen. Dies führt zu einer harten Anforderung, Änderungen zuzulassen.
James Moore
6

Hier ist eine Liste der Anschlusszeichen in Unicode. Sie finden sie nicht auf Ihrer Tastatur.

U + 005F LOW LINE _
U + 203F UNDERTIE ‿
U + 2040 CHARACTER TIE ⁀
U + 2054 INVERTED UNDERTIE ⁔
U + FE33 PRÄSENTATIONSFORMULAR FÜR VERTIKALE LOW LINE ︳
U + FE34 PRÄSENTATIONSFORMULAR FÜR VERTICAL WAVY LOW LINE ︴
U + FE4D DASHED LOW ﹍
U + FE4E CENTRELINE LOW LINE INE
U + FE4F WAVY LOW LINE ﹏
U + FF3F FULLWIDTH LOW LINE _

Simulant
quelle
5
Ich weiß nicht, welches Tastaturlayout Sie verwenden, aber ich kann _ (U + 005F) leicht genug
eingeben
4

Ein Verbindungszeichen wird verwendet, um zwei Zeichen zu verbinden.

In Java ist ein Verbindungszeichen dasjenige, für das Character.getType (int codePoint) / Character.getType (char ch) einen Wert zurückgibt, der Character.CONNECTOR_PUNCTUATION entspricht .

Beachten Sie, dass die Zeicheninformationen in Java auf dem Unicode-Standard basieren, der Verbindungszeichen identifiziert, indem ihnen die allgemeine Kategorie Pc zugewiesen wird, die ein Alias ​​für Connector_Punctuation ist .

Das folgende Code-Snippet:

for (int i = Character.MIN_CODE_POINT; i <= Character.MAX_CODE_POINT; i++) {
    if (Character.getType(i) == Character.CONNECTOR_PUNCTUATION
            && Character.isJavaIdentifierStart(i)) {
        System.out.println("character: " + String.valueOf(Character.toChars(i))
                + ", codepoint: " + i + ", hexcode: " + Integer.toHexString(i));
    }
}

Gibt die Verbindungszeichen aus, mit denen ein Bezeichner auf jdk1.6.0_45 gestartet werden kann

character: _, codepoint: 95, hexcode: 5f
character: ‿, codepoint: 8255, hexcode: 203f
character: ⁀, codepoint: 8256, hexcode: 2040
character: ⁔, codepoint: 8276, hexcode: 2054
character: ・, codepoint: 12539, hexcode: 30fb
character: ︳, codepoint: 65075, hexcode: fe33
character: ︴, codepoint: 65076, hexcode: fe34
character: ﹍, codepoint: 65101, hexcode: fe4d
character: ﹎, codepoint: 65102, hexcode: fe4e
character: ﹏, codepoint: 65103, hexcode: fe4f
character: _, codepoint: 65343, hexcode: ff3f
character: ・, codepoint: 65381, hexcode: ff65

Das Folgende wird auf jdk1.6.0_45 kompiliert:

int _, ‿, ⁀, ⁔, ・, ︳, ︴, ﹍, ﹎, ﹏, _,  = 0;

Anscheinend kann die obige Deklaration auf jdk1.7.0_80 & jdk1.8.0_51 für die folgenden zwei Verbindungszeichen nicht kompiliert werden (Abwärtskompatibilität ... oops !!!).

character: ・, codepoint: 12539, hexcode: 30fb
character: ・, codepoint: 65381, hexcode: ff65

Abgesehen von den Details konzentriert sich die Prüfung nur auf den lateinischen Grundzeichensatz .

Auch für Recht identifers in Java, ist die Spezifikation zur Verfügung gestellt hier . Verwenden Sie die Zeichenklassen-APIs, um weitere Details zu erhalten.

sxnamit
quelle
1

Eines der unterhaltsamsten Zeichen, das in Java-Bezeichnern zulässig ist (jedoch nicht am Anfang), ist das Unicode-Zeichen "Zero Width Non Joiner" (& zwnj;, U + 200C, https://en.wikipedia.org) / wiki / Zero-width_non-joiner ).

Ich hatte dies einmal in einem XML-Teil in einem Attributwert, der einen Verweis auf einen anderen Teil dieses XML enthält. Da der ZWNJ "Nullbreite" hat, kann er nicht gesehen werden (außer wenn er mit dem Cursor läuft, wird er direkt auf dem vorherigen Zeichen angezeigt). Es war auch nicht in der Protokolldatei und / oder Konsolenausgabe zu sehen. Aber es war die ganze Zeit da: Kopieren und Einfügen in Suchfelder hat es bekommen und somit die referenzierte Position nicht gefunden. Durch Eingabe des (sichtbaren Teils der) Zeichenfolge in das Suchfeld wurde jedoch die angegebene Position gefunden. Ich habe eine Weile gebraucht, um das herauszufinden.

Das Eingeben eines Zero-Width-Non-Joiner ist eigentlich ziemlich einfach (zu einfach), wenn das europäische Tastaturlayout verwendet wird, zumindest in seiner deutschen Variante, z. B. "Europatastatur 2.02" - es ist mit AltGr + "." Erreichbar, zwei Tasten, die Leider befinden sie sich auf den meisten Tastaturen direkt nebeneinander und können leicht versehentlich zusammengeschlagen werden.

Zurück zu Java: Ich dachte gut, Sie könnten einen Code wie diesen schreiben:

void foo() {
    int i = 1;
    int i = 2;
}

Mit dem zweiten habe ich einen Nicht-Joiner mit der Breite Null angehängt (das kann ich im obigen Code nicht tun, der im Editor von stackoverflow abgeschnitten wurde), aber das hat nicht funktioniert. IntelliJ (16.3.3) hat sich nicht beschwert, aber JavaC (Java 8) hat sich über einen bereits definierten Bezeichner beschwert - es scheint, dass JavaC das ZWNJ-Zeichen tatsächlich als Teil eines Bezeichners zulässt, aber wenn Reflektion verwendet wird, um zu sehen, was es tut, das ZWNJ Zeichen werden von der Kennung entfernt - etwas, das Zeichen wie ‿ nicht sind.

Ulrich Grepel
quelle
0

Die Liste der Zeichen, die Sie in Ihren Bezeichnern verwenden können (und nicht nur am Anfang), macht viel mehr Spaß:

for (int i = Character.MIN_CODE_POINT; i <= Character.MAX_CODE_POINT; i++)
    if (Character.isJavaIdentifierPart(i) && !Character.isAlphabetic(i))
        System.out.print((char) i + " ");

Die Liste lautet:

I wanted to post the output, but it's forbidden by the SO spam filter. That's how fun it is!

Es enthält die meisten Steuerzeichen! Ich meine Glocken und Scheiße! Sie können Ihren Quellcode zum Klingeln bringen! Oder verwenden Sie Zeichen, die nur manchmal angezeigt werden, z. B. den weichen Bindestrich.

Aleksandr Dubinsky
quelle
Es enthält \ u007f, das DEL-Zeichen. :-(
Todd O'Bryan