In che modo Java memorizza i caratteri UTF-16 nel suo tipo di char a 16 bit?

Secondo la specifica Java SE 7 , Java utilizza lo standard Unicode UTF-16 per rappresentare i caratteri. Quando immagina una String come una semplice matrice di variabili a 16 bit ciascuna contenente un carattere, la vita è semplice.

Sfortunatamente, ci sono punti di codice per i quali 16 bit semplicemente non sono sufficienti (credo fosse 16/17 di tutti i caratteri Unicode). Quindi, in una String , questo non pone alcun problema diretto, perché quando si desidera memorizzare uno di questi caratteri ~ 1.048.576 utilizzando due byte aggiuntivi, si useranno semplicemente due posizioni di matrice in quella String .

Questo, senza porre alcun problema diretto , funziona con String s, perché ci possono sempre essere altri due byte. Anche se si tratta di singole variabili che, a differenza della codifica UTF-16, hanno una lunghezza fissa di 16 bit , come possono essere memorizzati questi caratteri, e in particolare, come fa Java a farlo con il suo “char” a 2 byte tipo ?

La risposta è nella javadoc :

Il tipo di dati char (e quindi il valore che incapsula un object Character) si basa sulla specifica Unicode originale, che definisce i caratteri come entity framework a 16 bit a larghezza fissa. Lo standard Unicode è stato modificato per consentire i caratteri la cui rappresentazione richiede più di 16 bit.

L’intervallo di punti di codice legali è ora da U + 0000 a U + 10FFFF, noto come valore scalare Unicode. (Fare riferimento alla definizione della notazione U + n nello standard Unicode.) L’insieme di caratteri da U + 0000 a U + FFFF viene a volte indicato come Basic Plilingual Plane (BMP). I caratteri i cui punti di codice sono maggiori di U + FFFF sono chiamati caratteri supplementari. La piattaforma Java 2 utilizza la rappresentazione UTF-16 negli array di caratteri e nelle classi String e StringBuffer. In questa rappresentazione, i caratteri supplementari sono rappresentati come una coppia di valori char, il primo dall’intervallo alto-surrogati, (\ uD800- \ uDBFF), il secondo dall’intervallo di surrogati bassi (\ uDC00- \ uFFFF).

Un valore char, quindi, rappresenta i punti codice Basic Plilingual Plane (BMP), inclusi i punti di codice surrogato o le unità di codice della codifica UTF-16. Un valore int rappresenta tutti i punti di codice Unicode, inclusi i punti di codice supplementari. I 21 bit più bassi (meno significativi) di int sono utilizzati per rappresentare i punti di codice Unicode e gli 11 bit superiori (più significativi) devono essere zero.

Se non diversamente specificato, il comportamento rispetto ai caratteri supplementari e ai valori dei caratteri surrogati è il seguente: I metodi che accettano solo un valore char non possono supportare caratteri supplementari. Trattano i valori char dagli intervalli surrogati come caratteri non definiti. Ad esempio, Character.isLetter (‘\ uD840’) restituisce false, anche se questo valore specifico se seguito da qualsiasi valore di surrogato basso in una stringa rappresenterebbe una lettera. I metodi che accettano un valore int supportano tutti i caratteri Unicode, inclusi i caratteri supplementari. Ad esempio, Character.isLetter (0x2F81A) restituisce true perché il valore del punto di codice rappresenta una lettera (un ideogramma CJK). Nella documentazione dell’API Java, il punto di codice Unicode viene utilizzato per i valori di carattere nell’intervallo compreso tra U + 0000 e U + 10FFFF e l’unità di codice Unicode viene utilizzata per i valori di char a 16 bit che sono unità di codice della codifica UTF-16. Per ulteriori informazioni sulla terminologia Unicode, consultare il Glossario Unicode.

Detto semplicemente:

  • i 16 bit per una regola char sono stati progettati per una vecchia versione dello standard Unicode
  • a volte hai bisogno di due caratteri per rappresentare una runa unicode (punto codice) che non è nel piano multilingue di base. Questo tipo di “funziona” perché non si usano frequentemente i caratteri, specialmente per gestire le rune Unicode al di fuori del BMP.

Anche più semplice ha detto:

  • un java char non rappresenta un codepoint Unicode (beh, non sempre).

Per inciso, si può notare che l’evoluzione di Unicode per estendere il BMP ha reso UTF-16 globalmente irrilevante, ora che UTF-16 non abilita nemmeno un rapporto di byte-byte fisso. Ecco perché i linguaggi più moderni sono basati su UTF-8. Questo manifesto aiuta a capirlo.

Fondamentalmente, le stringhe memorizzano una sequenza di unità di codice UTF-16 … che non è la stessa cosa che memorizzare una sequenza di punti di codice Unicode.

Quando è richiesto un carattere al di fuori del piano multilingue di base, questo occupa due unità di codice UTF-16 all’interno della String .

La maggior parte delle operazioni Stringlength() , charAt , substring() ecc. charAt numeri di unità di codice UTF-16. Tuttavia, ci sono operazioni come codePointAt() che si occuperanno di punti di codice Unicode completi … sebbene gli indici siano ancora espressi in termini di unità di codice UTF-16.

EDIT: Se si desidera memorizzare un punto di codice non BMP in un singolo char , si è praticamente sfortunati. È come voler memorizzare più di 256 valori distinti in una variabile di byte … semplicemente non funziona. Seguendo le convenzioni per la rappresentazione di un punto di codice altrove (ad esempio in String ) è meglio usare solo una variabile int .