2015-05-09 10 views
27

Zunächst, ich entschuldige mich, wenn dies eine doppelte Frage ist. Ich habe viele ähnliche gefunden, aber keine, die meine Frage direkt betreffen.Verweis auf nicht endgültige Variable: Warum kompiliert dieser Code?

In Vorbereitung auf eine bevorstehende Prüfung, mache ich eine Vergangenheitsarbeit. Es hat eine Frage, die ein Code-Snippet gibt. Wir müssen angeben, ob es kompiliert wird, und wenn nicht, schreibe die Zeile, bei der der erste Compilerfehler auftritt, und erkläre es. Dies ist der Code-Schnipsel:

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); 
} 

ich es nicht zu kompilieren erwartet wurde als jtf nicht final. Ich testete meine Theorie, indem ich den obigen Code in Eclipse eingab, der den erwarteten Fehler markierte, aber kompilierte und lief gut. Erst nach über die JTextField mousing, dass ich die erwartete Fehlermeldung anzeigt:

java.lang.Error: Unresolved compilation problem: Cannot refer to the non-final local variable jtf defined in an enclosing scope

ich ein bisschen suchen hat, und entdeckte, dass Eclipse-seine eigene Version des Java-Compiler verwendet. Also habe ich die Datei außerhalb von Eclipse neu erstellt und über die Befehlszeile kompiliert/ausgeführt. Es kompilierte ohne Fehler oder Warnungen, und wenn man über das Textfeld mogelte, zeigte das gewünschte java.awt.Point[x=...,y=...] an.

Mein Verständnis von anonymen inneren Klassen ist, dass sie zugreifen können:

  • Felder der umgebenden Klasse
  • Methoden der umschließenden Klasse
  • Lokale Variablen des umschließenden Umfang, vorausgesetzt, sie sind final

Also was fehlt mir? Nach dem, was ich weiß, sollte dieser Code nicht funktionieren.

Antwort

33

Ich denke, Sie kompilieren mit Java 8. Hier ist Ihre jtf Variable effektiv endgültig, so dass es gut kompiliert. Eine Variable ist effektiv endgültig, wenn ihr Wert nach der Initialisierung nie geändert wird.

Siehe auch Local Classes:

However, starting in Java SE 8, a local class can access local variables and parameters of the enclosing block that are final or effectively final. A variable or parameter whose value is never changed after it is initialized is effectively final.

und

Accessing Local Variables of the Enclosing Scope, and Declaring and Accessing Members of the Anonymous Class

Like local classes, anonymous classes can capture variables; they have the same access to local variables of the enclosing scope:

  • An anonymous class has access to the members of its enclosing class.

  • An anonymous class cannot access local variables in its enclosing scope that are not declared as final or effectively final.

[...]

Wenn Sie versucht mit:

javac -source 1.7 MyFile.java 

Sie Ihre Ex haben Fehler erkannt.

.java:13: error: local variable jtf is accessed from within inner class; needs to be declared final 
       jtf.setText(evt.getLocationOnScreen().toString()); 
       ^
1 error 

Die Antwort der Prüfungsfrage lautet also: Sie kompiliert nur, wenn Sie Java 8+ verwenden.

15

Java 8 hat die Möglichkeit hinzugefügt, auf "effectively final" Variablen zuzugreifen. Das Schlüsselwort final ist nicht mehr erforderlich, solange eine Variable nach der Initialisierung nie geändert wird.

1

Es kann in Java8 arbeiten, wie die Belastung auf Effectively Final ist, was bedeutet, sobald der Wert jtf zugewiesen wird, sollte es nicht nach den Wards geändert werden.Wie in Java doc:

A variable or parameter whose value is never changed after it is initialized is effectively final.

0

Scheint, dass Ihre Eclipse-IDE Java 7-Compiler verwendet. Um dies in Java 8 zu ändern, verwenden Sie Project-> Properties-> Java Compiler-> Compiler Compliance Level.

Verwandte Themen