Pregunta

El siguiente método no funciona porque el bloque interno declara una variable del mismo nombre que una en el bloque externo. Aparentemente, las variables pertenecen al método o clase en el que se declaran, no al bloque en el que se declaran, por lo que no puedo escribir un pequeño bloque temporal para la depuración que empuja una variable del alcance externo a sombra por un momento:

void methodName() {
  int i = 7;
  for (int j = 0; j < 10; j++) {
    int i = j * 2;
  }
}

Casi todos los lenguajes de ámbito de bloque que he usado lo respaldan, incluidos los pequeños lenguajes triviales para los que escribí intérpretes y compiladores en la escuela. Perl puede hacer esto, al igual que Scheme, e incluso C. ¡Incluso PL / SQL lo admite!

¿Cuál es la razón de esta decisión de diseño para Java?

Editar: como alguien señaló, Java tiene un alcance de bloque. ¿Cómo se llama el concepto sobre el que estoy preguntando? Desearía poder recordar más de esas clases de diseño de idiomas. :)

¿Fue útil?

Solución

Creo que la razón es que la mayoría de las veces, eso no es intencional, es una falla de programación o lógica.

en un ejemplo tan trivial como el suyo, es obvio, pero en un gran bloque de código, volver a declarar accidentalmente una variable puede no ser obvio.

ETA: también podría estar relacionado con el manejo de excepciones en java. Pensé que parte de esta pregunta se discutió en una pregunta relacionada con por qué las variables declaradas en una sección de prueba no estaban disponibles en los ámbitos catch / finalmente.

Otros consejos

Bueno, estrictamente hablando, Java tiene declaraciones de variable de ámbito de bloque; entonces este es un error:

void methodName() {
  for (int j = 0; j < 10; j++) {
    int i = j * 2;
  }
  System.out.println(i); // error
}

Porque 'i' no existe fuera del bloque for.

El problema es que Java no le permite crear una variable con el mismo nombre de otra variable que se declaró en un bloque externo del mismo método. Como han dicho otras personas, supuestamente esto se hizo para evitar errores que son difíciles de identificar.

Debido a que no es raro que los escritores hagan esto intencionalmente y luego lo arruinen por completo al olvidar que ahora hay dos variables con el mismo nombre. Cambian el nombre de la variable interna, pero dejan un código que usa la variable, que ahora usa de manera no esencial la variable sombreada previamente. Esto da como resultado un programa que aún se compila, pero se ejecuta con errores.

Del mismo modo, no es raro sombrear accidentalmente variables y cambiar el comportamiento del programa. Sin saberlo, sombrear una variable existente puede cambiar el programa tan fácilmente como sombrear una variable como mencioné anteriormente.

Hay tan pocos beneficios al permitir este sombreado que lo descartaron como demasiado peligroso. En serio, simplemente llame a su nueva variable de otra manera y el problema desaparecerá.

Supongo que conduce a errores que son difíciles de detectar. Es similar en C #.

Pascal no admite esto, ya que debe declarar variables por encima del cuerpo de la función.

La suposición subyacente en esta pregunta es incorrecta.

Java tiene un alcance de nivel de bloque. Pero también tiene una jerarquía de alcance, por lo que puede hacer referencia a i dentro del bucle for , pero no a j fuera del bucle for .

public void methodName() {
  int i = 7;
  for (int j = 0; j < 10; j++) {
    i = j * 2;
  }

  //this would cause a compilation error!
  j++;
}

No puedo por mi vida entender por qué querrías que el alcance se comportara de otra manera. Sería imposible determinar a qué i se refería dentro del ciclo for, y apuesto a que es probable que el 99.999% del tiempo desee referirse al i dentro del método.

otra razón: si se permitiera este tipo de declaración de variable, la gente querría (¿necesita?) una forma de acceder a las variables de bloque externo. puede ser algo como "exterior" se agregaría la palabra clave:

void methodName() {
    int i = 7;
    for (int j = 0; j < 10; j++) {
        int i = outer.i * 2;
        if(i > 10) {
            int i = outer.outer.i * 2 + outer.i;
        }
    }
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top