Este es el código que tengo:
class HelloWorld { char[] foo = {'a', 'b'}; // This will compile void foo() { for (char foo : foo) { } } // This will not compile void bar() { for (char foo = 0; foo < foo.length; foo++) { } } } ¿Cómo es que foo compila pero la bar de compilación falla con:
Error: char cannot be dereferenced¿Cuál es la diferencia entre las dos declaraciones de bucle que hacen que el bucle foo compile pero que la barra falle?
Podemos ver la diferencia observando la descripción de JLS§14.14.2 de cómo funciona el for mejorado cuando se maneja una matriz:
La instrucción for mejorada es equivalente a una instrucción for básica de la forma:
T[] #a = Expression; L1: L2: ... Lm: for (int #i = 0; #i < #a.length; #i++) { {VariableModifier} TargetType Identifier = #a[#i]; Statement }
Observe cómo se declara la variable dentro del cuerpo del ciclo, no en el encabezado del ciclo. Es decir, su función foo es así:
void foo() { { // Freestanding block for scope, though not really needed as `foo` has // nothing else in it char[] a = foo; // T[] #a = Expression; for (int i = 0; i < a.length; i++) { char foo = a[i]; // {VariableModifier} TargetType Identifier = #a[#i]; } } } Es por eso que se sale con la suya con el sombreado en el for mejorado, y no en el for tradicional, que necesita acceder a la matriz original (para obtener su length , para obtener la entrada para i , etc.).
Más información sobre el bucle for mejorado en ¿Cómo funciona el bucle 'for each' de Java? y sus respuestas.
La especificación del lenguaje Java define los alcances de sus dos char foo de manera diferente:
El alcance de una variable local declarada en la parte ForInit de una instrucción
forbásica (§14.14.1) incluye todo lo siguiente:
- Su propio inicializador
- Cualquier declarante adicional a la derecha en la parte ForInit de la instrucción
for- Las partes Expression y ForUpdate de la instrucción
for- La Declaración contenida
El ámbito de una variable local declarada en la parte FormalParameter de una instrucción
formejorada (§14.14.2) es la instrucción contenida.
Eso explica perfectamente su comportamiento observado: el foo local está dentro del alcance en la cláusula de control del bucle for básico (en todas partes a la derecha de su declaración) y, por lo tanto, sombrea al otro foo allí, pero en el bucle for mejorado su alcance es solo la declaración de bucle: no está dentro del alcance en ninguna parte de la cláusula de control de bucle.