Cosa sono i "caratteri di connessione" negli identificatori Java?


208

Sto leggendo per SCJP e ho una domanda su questa riga:

Gli identificatori devono iniziare con una lettera, un carattere di valuta ($) o un carattere di connessione come il trattino basso (_). Gli identificatori non possono iniziare con un numero!

Indica che un nome identificativo valido può iniziare con un carattere di connessione come il carattere di sottolineatura. Pensavo che i trattini bassi fossero l'unica opzione valida? Quali altri personaggi di collegamento ci sono?


2
Per quanto riguarda "un carattere di valuta": i visitatori del Regno Unito a questa domanda possono essere sorpresi e interessati a sapere che, coerentemente con la possibilità di iniziare con un "carattere di valuta", gli identificatori Java possono, legalmente, iniziare con il simbolo della sterlina (£).
8bitjunkie,

11
Si noti che da Java 8 _è un identificatore "obsoleto". In particolare, il compilatore emette il seguente avviso: (l'uso di '_' come identificatore potrebbe non essere supportato nelle versioni dopo Java SE 8) .
aioobe,

4
@aioobe Yup. Brian Goetz afferma che stanno "reclamando" _per l'uso in funzioni linguistiche future . Gli identificatori che iniziano con un carattere di sottolineatura sono ancora a posto, ma un singolo carattere di sottolineatura è un errore se utilizzato come nome di parametro lambda e un avviso ovunque.
Boann,

1
Per il bytecode, tutto ciò in sequenza che non contenga . ; [ / < > :va: stackoverflow.com/questions/26791204/... docs.oracle.com/javase/specs/jvms/se7/html/... Tutto il resto è un Java-unica restrizione.
Ciro Santilli 5 冠状 病 六四 事件 法轮功

@Boann La cosa divertente è che non ne consentono l'uso in lambdas, ma probabilmente tornerà come identificatore "ignora questo argomento", che verrà utilizzato ad esempio in lambdas. Ho solo cercato di usare in questo modo: _, _ -> doSomething();.
user31389

Risposte:


268

Ecco un elenco di caratteri di collegamento. Questi sono i caratteri usati per collegare le parole.

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

Questo viene compilato su Java 7.

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

Un esempio. In questo caso tpè il nome di una colonna e il valore per una determinata riga.

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

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

Il seguente

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 + " ");
}

stampe

$ _ ¢ £ ¤ ¥ ؋ ৲ ৳ ৻ ૱ ௹ ฿ ៛ ‿ ⁀ ⁔ ₠ ₡ ₢ ₣ ₤ ₥ ₦ ₧ ₨ ₩ ₪ ₫ € ₭ ₮ ₯ ₰ ₱ ₱ ₳ ₴ ₵ ₶ ₷ ₸ ₹ ꠸ ﷼ ︳ ︴ ﹎ ﹎ ﹩ $ _ ¢ £ ¥ ₩


109
Non vedo l'ora che arrivi il giorno in cui erediterò del codice che utilizza questi identificatori!
Marko Topolnik,

58
@MarkoTopolnik Fai attenzione a ciò che desideri. ;)
Peter Lawrey,

3
BTW È possibile utilizzare anche uno qualsiasi dei simboli di valuta. int ৲, ¤, ₪₪₪₪;: D
Peter Lawrey,

17
Potrei buttarne uno o due nel mio codice, solo per calci! E per verificare se il sistema di compilazione è veramente conforme a UTF-8.
Marko Topolnik,

82
@GrahamBorland Che ne dici if( ⁀ ‿ ⁀ == ⁀ ⁔ ⁀) o if ($ == $)o if (¢ + ¢== ₡)oif (B + ︳!= ฿)
Peter Lawrey

25

scorrere tutti i caratteri 65k e chiedere Character.isJavaIdentifierStart(c). La risposta è: "undertie" decimale 8255


14
Non ho potuto resistere (alla Scala): (1 to 65535).map(_.toChar).filter(Character.isJavaIdentifierStart).size- produce 48529 caratteri ...
Tomasz Nurkiewicz il

sembra che ci siano alcuni personaggi vicino a 65k e 12k e 8.5k ecc.
Markus Mikkolainen il

non cede se dici "! isLetter" e "! isDigit"
Markus Mikkolainen il

2546 + 2547 almeno "disegno scatola ..."
Markus Mikkolainen,

3
Conteggio totale = 90648, ma vado a Character.MAX_CODE_POINT, che è probabilmente più di 2<<16.
Martijn Courteaux,

7

La specifica definitiva di un identificatore Java legale è disponibile nella specifica del linguaggio Java .


3
Non sono sicuro che in realtà risponda pienamente alla domanda (implicita) di quali caratteri possono avviare un identificatore Java. I seguenti collegamenti finiscono in Character.isJavaIdentifierStart () che indica che un personaggio può avviare un identificatore Java se e solo se una delle seguenti condizioni è vera: ... ch è un simbolo di valuta ( come "$"); ch è un carattere di punteggiatura di collegamento ( come "_").
un CVn il

1
Sembra che la specifica lasci la lista finale di caratteri accettabili fino all'implementazione, quindi potrebbe essere potenzialmente diversa per tutti.
Greg Hewgill,

3
@GregHewgill Sarebbe sciocco, considerando quanto sia strettamente specificato tutto il resto. Penso che queste siano effettive classi di caratteri Unicode, che sono definite (dove altro?) Nello standard Unicode. isJavaIdentifierStart () menziona getType (), e il simbolo di valuta e la punteggiatura del connettore sono entrambi tipi che possono essere restituiti da quella funzione, quindi gli elenchi potrebbero essere forniti lì. "Categoria generale" è in effetti un termine specifico nello standard Unicode. Così i valori validi sarebbero L[tutti], Nl, Sc, Pc.
Casuale 832

3
@GregHewgill è corretto. La specifica è breve e chiara ed è definita da Character.isJavaIdentifierStart () e Character.isJavaIdentifierPart (). La fine. La cosa fondamentale da ricordare è che Unicode si sta evolvendo; non cadere nella trappola di pensare ai set di caratteri come finiti (il latino è un terribile esempio; ignoralo). I personaggi vengono creati continuamente. Chiedi ai tuoi amici giapponesi. Aspettati che gli identificatori Java legali cambino nel tempo, e questo è intenzionale. Il punto è lasciare che le persone scrivano codice in lingue umane. Ciò comporta un duro requisito per consentire il cambiamento.
James Moore,

6

Ecco un elenco di caratteri connettore in Unicode. Non li troverai sulla tastiera.

U + 005F LOW LINE _
U + 203F UNDERTIE ‿
U + 2040 CHARACTER TIE ⁀
U + 2054 INVERTED UNDERTIE ⁔
U + FE33 MODULO DI PRESENTAZIONE PER VERTICAL LOW LINE ︳
U + FE34 MODULO DI PRESENTAZIONE PER VERTICALE WAVY LOW LINE ︴
U + FE4D DASHED LOW LINE ﹍
U + FE4E CENTRELINE LOW LINE ﹎
U + FE4F WAVY LOW LINE ﹏
U + FF3F FULLWIDTH LOW LINE _


5
Non so quale layout di tastiera stai usando, ma posso sicuramente digitare _ (U + 005F) abbastanza facilmente :)
bdonlan

4

Un carattere di connessione viene utilizzato per connettere due personaggi.

In Java, un carattere di connessione è quello per cui Character.getType (int codePoint) / Character.getType (char ch) restituisce un valore uguale a Character.CONNECTOR_PUNCTUATION .

Si noti che in Java, le informazioni sui caratteri si basano sullo standard Unicode che identifica i caratteri di connessione assegnando loro la categoria generale Pc, che è un alias per Connector_Punctuation .

Il seguente frammento di codice,

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));
    }
}

stampa i caratteri di connessione che possono essere utilizzati per avviare un identificatore su jdk1.6.0_45

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

Le seguenti compilazioni su jdk1.6.0_45,

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

Apparentemente, la dichiarazione di cui sopra non può essere compilata su jdk1.7.0_80 e jdk1.8.0_51 per i seguenti due caratteri di connessione (compatibilità con le versioni precedenti ... oops !!!),

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

Comunque, a parte i dettagli, l'esame si concentra solo sul set di caratteri latini di base .

Inoltre, per gli identificatori legali in Java, le specifiche sono fornite qui . Utilizzare le API della classe di caratteri per ottenere maggiori dettagli.


1

Uno dei personaggi più divertenti, consentiti negli identificatori Java (comunque non all'inizio) è il personaggio unicode chiamato "Zero Width Non Joiner" (& zwnj ;, U + 200C, https://en.wikipedia.org / wiki / Zero-width_non-joiner ).

L'ho avuto una volta in un pezzo di XML all'interno di un valore di attributo che conteneva un riferimento a un altro pezzo di tale XML. Poiché ZWNJ è "larghezza zero" non può essere visto (tranne quando si cammina insieme al cursore, viene visualizzato prima sul personaggio). Inoltre, non è stato visualizzato nel file di log e / o nell'output della console. Ma era sempre lì: copia e incolla nei campi di ricerca lo ha ottenuto e quindi non ha trovato la posizione indicata. Digitando la (parte visibile della) stringa nel campo di ricerca è stata tuttavia trovata la posizione indicata. Mi ci è voluto un po 'per capirlo.

Digitare uno Zero-Width-Non-Joiner è in realtà abbastanza facile (troppo facile) quando si utilizza il layout della tastiera europea, almeno nella sua variante tedesca, ad esempio "Europatastatur 2.02" - è raggiungibile con AltGr + ".", Due tasti che purtroppo si trovano uno accanto all'altro sulla maggior parte delle tastiere e possono essere facilmente colpiti insieme accidentalmente.

Torna a Java: ho pensato bene, potresti scrivere del codice in questo modo:

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

con il secondo ho aggiunto un non-joiner a larghezza zero (non posso farlo nel codice sopra riportato nell'editor dello stackoverflow), ma non ha funzionato. IntelliJ (16.3.3) non si è lamentato, ma JavaC (Java 8) si è lamentato di un identificatore già definito - sembra che JavaC in realtà permetta al personaggio ZWNJ come parte di un identificatore, ma quando si usa la riflessione per vedere cosa fa, lo ZWNJ il personaggio viene rimosso dall'identificatore - qualcosa che caratteri come ‿ non lo sono.


0

L'elenco dei personaggi che puoi usare all'interno dei tuoi identificatori (piuttosto che solo all'inizio) è molto più divertente:

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 + " ");

L'elenco è:

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

Include la maggior parte dei personaggi di controllo! Intendo campane e merda! Puoi far suonare il tuo codice sorgente su fn bell! Oppure usa i caratteri che verranno visualizzati solo a volte, come il trattino morbido.


Include \ u007f, il carattere DEL. :-(
Todd O'Bryan il
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.