java - valor - Referencia a variable no final: ¿por qué se compila este código?
paso por referencia en java (4)
Java 8 agregó la capacidad de acceder a las variables "efectivamente finales" . La palabra clave final
ya no es necesaria siempre que una variable nunca se cambie después de que se inicialice.
En primer lugar, me disculpo si esta es una pregunta duplicada. Encontré muchos similares, pero ninguno que aborda directamente mi pregunta.
En preparación para un próximo examen, estoy haciendo un trabajo anterior. Tiene una pregunta que da un fragmento de código. Debemos indicar si compila, y si no, escribir la línea en la que se produce el primer error del compilador y explicarlo. Este es el fragmento:
public static void main(String[] args) {
JFrame f = new JFrame("hi");
JTextField jtf = new JTextField(50);
jtf.addMouseMotionListener(new MouseMotionAdapter() {
public void mouseMoved(MouseEvent evt) {
jtf.setText(evt.getLocationOnScreen().toString());
}
});
f.add(jtf);
f.setVisible(true);
}
Esperaba que no se compilara ya que jtf
no es final
. Probé mi teoría ingresando el código anterior en Eclipse, que marcó el error esperado, pero compiló y funcionó bien. Fue solo después de pasar el JTextField
sobre el campo JTextField
que obtuve el error esperado:
java.lang.Error: Problema de compilación no resuelto: no se puede hacer referencia a la variable local no final jtf definida en un ámbito de cierre
Hice un poco de búsqueda y descubrí que Eclipse usa su propia versión del compilador de Java. Así que rehice el archivo fuera de Eclipse y lo compilé / ejecuté a través de la línea de comandos. Se compiló sin errores ni advertencias, y al pasar el mouse sobre el campo de texto, se mostró el java.awt.Point[x=...,y=...]
deseado java.awt.Point[x=...,y=...]
.
Mi comprensión de las clases internas anónimas es que pueden acceder a:
- Campos de la clase envolvente.
- Métodos de la clase envolvente.
- Variables locales del ámbito de cierre, siempre que sean
final
Entonces, ¿qué me estoy perdiendo? Según lo que sé, este código no debería funcionar .
Parece que su Eclipse IDE usa el compilador Java 7. Para cambiar esto a Java 8 use Proyecto-> Propiedades-> Compilador Java-> Nivel de cumplimiento del compilador.
Puede funcionar en Java8
ya que el énfasis está en Effectively Final
que significa que una vez que el valor se asigna a jtf
, no se debe cambiar después de las salas. Según el documento de Java:
Una variable o parámetro cuyo valor nunca se cambia después de su inicialización es efectivamente final.
Supongo que está compilando con Java 8. Aquí su variable jtf
es efectivamente final, por lo que se compila bien. Una variable es efectivamente final si su valor nunca se cambia después de inicializarla.
Ver también Clases Locales :
Sin embargo, a partir de Java SE 8, una clase local puede acceder a las variables y parámetros locales del bloque adjunto que son finales o efectivamente finales. Una variable o parámetro cuyo valor nunca se cambia después de su inicialización es efectivamente final.
y
Al igual que las clases locales, las clases anónimas pueden capturar variables; Tienen el mismo acceso a las variables locales del ámbito de aplicación:
Una clase anónima tiene acceso a los miembros de su clase adjunta.
Una clase anónima no puede acceder a las variables locales en su ámbito que no se declaran como final o efectivamente final.
[...]
Si lo intentaste con:
javac -source 1.7 MyFile.java
tendrás el error esperado.
.java:13: error: local variable jtf is accessed from within inner class; needs to be declared final
jtf.setText(evt.getLocationOnScreen().toString());
^
1 error
Entonces, la respuesta de la pregunta del examen es: se compila solo si está utilizando Java 8+.