Hay muchas técnicas básicas que utilizamos habitualmente sin siquiera pensarlo. Bueno, ¿qué pasa si lo piensas y observas cómo se implementan algunos métodos aparentemente simples? Creo que esto nos ayudará a acercarnos un paso más a Java). Imaginemos una situación en la que necesitamos extraer un determinado carácter en alguna cadena. ¿Cómo podemos hacer esto en Java? Por ejemplo, llamando al
Java String charAt
. charAt()
Hablaremos sobre el método en el artículo de hoy.
Sintaxis
char charAt(int index)
devuelve el valor de carácter en el índice especificado. El índice oscila entre 0 y length()-1
. Es decir, el primer char
valor de la secuencia está en index 0
, el siguiente está en , index 1
etc., como es el caso de la indexación de matrices.
Ejemplo
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 primera línea toma el primer carácter, la segunda línea toma el segundo y así sucesivamente. Dado que aquí no se usa println
pero print
, sin una nueva línea, obtendremos el siguiente resultado en la consola:
Java
Si char
el índice dado se representa como Unicode, el resultado del método java charAt()
será el carácter que representa este Unicode:
System.out.println("J\u0061vaRush".charAt(1));
Salida de consola:
a
¿Qué hay "debajo del capó"?
¿Cómo funciona, preguntas? El hecho es que cada objetoString
contiene una matriz byte
con bytes de los elementos de una cadena determinada:
private final byte[] value;
Y aquí está el método en sí chatAt
:
public char charAt(int index) {
if (isLatin1()) {
return StringLatin1.charAt(value, index);
} else {
return StringUTF16.charAt(value, index);
}
}
isLatin1
- una bandera que indica si nuestra cadena contiene solo caracteres latinos o no. Esto determina qué método se llamará a continuación.
esLatin1 = verdadero
Si la cadena contiene sólo caracteres latinos, se llama a un métodocharAt
de clase estática StringLatin1
:
public static char charAt(byte[] value, int index) {
if (index < 0 || index >= value.length) {
throw new StringIndexOutOfBoundsException(index);
}
return (char)(value[index] & 0xff);
}
El primer paso es verificar que el índice entrante sea mayor o igual a 0, y que no vaya más allá del array de bytes interno, y si este no es el caso, entonces se lanza una excepción new StringIndexOutOfBoundsException(index)
. Si se pasan las comprobaciones, se toma el elemento que necesitamos. Al final vemos:
&
se extiende para operación binaria abyte
bit a bit0xff
no hace nada más que&
requiere un argumento(char)
convierte datos de una tabla ASCII achar
esLatin1 = falso
Si no tuviéramos solo caracteres latinos, se usará la claseStringUTF16
y se llamará a su método estático:
public static char charAt(byte[] value, int index) {
checkIndex(index, value);
return getChar(value, index);
}
Que a su vez llama:
public static void checkIndex(int off, byte[] val) {
String.checkIndex(off, length(val));
}
Y delega a un método estático String
:
static void checkIndex(int index, int length) {
if (index < 0 || index >= length) {
throw new StringIndexOutOfBoundsException("index " + index +
", length " + length);
}
}
Aquí, de hecho, se comprueba si el índice es válido: nuevamente, si es positivo o cero y si no ha sobrepasado los límites de la matriz. Pero en una clase StringUTF16
en un método, charAt
llamar al segundo método será más interesante:
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));
}
Comencemos a analizar lo que realmente está sucediendo aquí. El primer paso al comienzo del método es otra verificación de la validez del índice. Para comprender lo que sucede a continuación, debe comprender: cuando un carácter no latino ingresa a la matriz value
, se representa mediante dos bytes (dos celdas de la matriz). Si tenemos una cadena de dos caracteres cirílicos - "av", entonces:
- para 'a' es un par de bytes: 48 y 4;
- para 'en' - 50 y 4.
value
- {48, 4, 50, 4} En realidad, este método funciona con dos celdas de una matriz value
. Por lo tanto, el siguiente paso es un desplazamiento index <<= 1;
para llegar directamente al índice del primer byte del carácter deseado en la matriz value
. Ahora digamos que tenemos una cadena "абвг"
. Entonces la matriz de valores se verá así: {48, 4, 49, 4, 50, 4, 51, 4}. Solicitamos el tercer elemento de la cadena y luego la representación binaria es 00000000 00000011. Cuando lo desplazamos en 1, obtenemos 00000000 00000110, es decir index = 6
. Para actualizar sus conocimientos sobre operaciones bit a bit, puede leer este artículo . También vemos algunas variables: HI_BYTE_SHIFT
en este caso es 0. LO_BYTE_SHIFT
en este caso es 8. En la última línea de este método:
- Se toma un elemento de la matriz de valores y se desplaza bit a bit en
HI_BYTE_SHIFT
, es decir, 0, mientras se aumentaindex +1
.En el ejemplo con la cadena
"абвг"
, el sexto byte (51) permanecería así, pero al mismo tiempo el índice aumentaría a 7. - Después de esto, se toma el siguiente elemento de la matriz y se desplaza bit a bit de la misma manera, pero con LO_BYTE_SHIFT, es decir, 8 bits.
Y si tuviéramos el byte 4, que tiene una representación binaria: 00000000 00000100, luego de cambiar 8 bits tendremos 00000100 00000000. Si es un número entero, 1024.
- A continuación, para estos dos valores, sigue la operación
| (OR)
.Y si tuviéramos los bytes 51 y 1024, que en representación binaria se parecían a 00000000 00110011 y 00000100 00000000, luego de la operación
OR
obtendremos 00000100 00110011, lo que significa el número 1075 en el sistema decimal.Bueno, al final, el número 1075 se convierte al tipo char, y al convertir int -> char se usa la tabla ASCII, y en ella, debajo del número 1075, está el carácter 'g'.
charAt()
en programación Java.
GO TO FULL VERSION