Esistono molte tecniche di base che utilizziamo regolarmente senza nemmeno pensarci. Bene, cosa succede se ci pensi e guardi come vengono implementati alcuni metodi apparentemente semplici? Penso che questo ci aiuterà ad avvicinarci di più a Java) Immaginiamo una situazione in cui dobbiamo estrarre un determinato carattere in una stringa. Come possiamo farlo in Java? Ad esempio, chiamando il
Java String charAt
. charAt()
Parleremo del metodo nell'articolo di oggi.
Sintassi
char charAt(int index)
restituisce il valore del carattere nell'indice specificato. L'indice varia da 0 a length()-1
. Cioè, il primo char
valore della sequenza è in index 0
, il successivo è in , index 1
ecc., come nel caso dell'indicizzazione degli array.
Esempio
public static void main(String[] args) {
System.out.print("JavaRush".charAt(0));
System.out.print("JavaRush".charAt(1));
System.out.print("JavaRush".charAt(2));
System.out.print("JavaRush".charAt(3));
}
La prima riga prende il primo carattere, la seconda il secondo e così via. Poiché not println
, but viene utilizzato qui print
, senza una nuova riga, otterremo il seguente output sulla console:
Java
Se char
l'indice fornito è rappresentato come Unicode, il risultato del metodo java charAt()
sarà il carattere che rappresenta questo Unicode:
System.out.println("J\u0061vaRush".charAt(1));
Uscita console:
a
Cosa c'è "sotto il cofano"
Come funziona, chiedi? Il fatto è che ogni oggettoString
contiene un array byte
con byte degli elementi di una determinata stringa:
private final byte[] value;
Ed ecco il metodo stesso chatAt
:
public char charAt(int index) {
if (isLatin1()) {
return StringLatin1.charAt(value, index);
} else {
return StringUTF16.charAt(value, index);
}
}
isLatin1
- un flag che indica se la nostra stringa contiene solo caratteri latini oppure no. Ciò determina quale metodo verrà chiamato successivamente.
isLatin1 = vero
Se la stringa contiene solo caratteri latini, viene chiamato un metodocharAt
di classe statica StringLatin1
:
public static char charAt(byte[] value, int index) {
if (index < 0 || index >= value.length) {
throw new StringIndexOutOfBoundsException(index);
}
return (char)(value[index] & 0xff);
}
Il primo passo è verificare che l'indice in ingresso sia maggiore o uguale a 0 e che non vada oltre l'array di byte interno e, in caso contrario, viene lanciata un'eccezione new StringIndexOutOfBoundsException(index)
. Se i controlli vengono superati, viene preso l'elemento di cui abbiamo bisogno. Alla fine vediamo:
&
si estende per l'operazione binaria abyte
bit per bit0xff
non fa altro che&
richiede una discussione(char)
converte i dati da una tabella ASCII inchar
isLatin1 = falso
Se avessimo più di semplici caratteri latini, verrà utilizzata la classeStringUTF16
e il suo metodo statico verrà chiamato:
public static char charAt(byte[] value, int index) {
checkIndex(index, value);
return getChar(value, index);
}
Che a sua volta chiama:
public static void checkIndex(int off, byte[] val) {
String.checkIndex(off, length(val));
}
E delega ad un metodo statico String
:
static void checkIndex(int index, int length) {
if (index < 0 || index >= length) {
throw new StringIndexOutOfBoundsException("index " + index +
", length " + length);
}
}
Qui infatti si verifica se l'indice è valido: ancora, se è positivo o zero, e se non è andato oltre i limiti dell'array. Ma in una classe StringUTF16
di un metodo, charAt
chiamare il secondo metodo sarà più interessante:
static char getChar(byte[] val, int index) {
assert index >= 0 && index < length(val) : "Trusted caller missed bounds check";
index <<= 1;
return (char)(((val[index++] & 0xff) << HI_BYTE_SHIFT) |
((val[index] & 0xff) << LO_BYTE_SHIFT));
}
Cominciamo ad analizzare cosa sta realmente accadendo qui. Il primo passo all'inizio del metodo è un altro controllo della validità dell'indice. Per capire cosa succede dopo, devi capire: quando un carattere non latino entra nell'array value
, è rappresentato da due byte (due celle dell'array). Se abbiamo una stringa di due caratteri cirillici - "av", allora:
- per 'a' questa è una coppia di byte: 48 e 4;
- per 'in' - 50 e 4.
value
- {48, 4, 50, 4} In realtà, questo metodo funziona con due celle dell'array value
. Pertanto, il passo successivo è uno spostamento index <<= 1;
per arrivare direttamente all'indice del primo byte del carattere desiderato nell'array value
. Ora diciamo che abbiamo una stringa "абвг"
. Quindi l'array di valori sarà simile a questo: {48, 4, 49, 4, 50, 4, 51, 4}. Chiediamo il terzo elemento della stringa, quindi la rappresentazione binaria è 00000000 00000011. Se spostato di 1, otteniamo 00000000 00000110, cioè index = 6
. Per rinfrescare le tue conoscenze sulle operazioni bit a bit, puoi leggere questo articolo . Vediamo anche alcune variabili: HI_BYTE_SHIFT
in questo caso è 0. LO_BYTE_SHIFT
in questo caso è 8. Nell'ultima riga di questo metodo:
- Un elemento viene preso dall'array di valori e spostato bit a bit di
HI_BYTE_SHIFT
, ovvero 0, aumentandoindex +1
.Nell'esempio con la stringa
"абвг"
, il sesto byte - 51 - rimarrebbe tale, ma contemporaneamente l'indice aumenterebbe a 7. - Successivamente, l'elemento successivo dell'array viene preso e spostato bit per bit allo stesso modo, ma di LO_BYTE_SHIFT, cioè di 8 bit.
E se avessimo il byte 4, che ha una rappresentazione binaria - 00000000 00000100, dopo lo spostamento di 8 bit avremo 00000100 00000000. Se è un numero intero - 1024.
- Successivamente, per questi due valori, segue l'operazione
| (OR)
.E se avessimo i byte 51 e 1024, che nella rappresentazione binaria assomigliavano a 00000000 00110011 e 00000100 00000000, dopo l'operazione
OR
otterremo 00000100 00110011, che significa il numero 1075 nel sistema decimale.Bene, alla fine, il numero 1075 viene convertito nel tipo char e quando si converte int -> char viene utilizzata la tabella ASCII e in essa, sotto il numero 1075, c'è il carattere 'g'.
charAt()
nella programmazione Java.
GO TO FULL VERSION