2014-10-27 9 views
5

Prima di java 8 una classe interna poteva accedere agli oggetti esterni solo se erano dichiarati definitivi. Tuttavia ora quando eseguo il codice di esempio (dal basso) su javaSE 1.8 non ci sono errori di compilazione e il programma funziona correttamente.Le classi anonime possono accedere agli oggetti esterni non finali in java 8?

Perché l'hanno cambiato e come funziona ora?

codice di esempio da Java 7 tutorial:

public class MOuter { 
    private int m = (int) (Math.random() * 100); 

    public static void main(String[] args) { 
     MOuter that = new MOuter(); 
     that.go((int) (Math.random() * 100), (int) (Math.random() * 100)); 
    } 

    public void go(int x, final int y){ 
     int a = x + y; 
     final int b = x - y; 

     class MInner{ 
      public void method(){ 
       System.out.println("m is "+m); 
       System.out.println("x is "+x); // supposedly illegal - 'x' not final 
       System.out.println("y is: "+y); 
       System.out.println("a is "+a); // supposedly illegal? - 'a' not final 
      } 
     }  
     MInner that = new MInner(); 
     that.method(); 
    } 
} 
+1

Cosa ha detto JB. Ora è "efficacemente definitivo". È stato aggiunto per supportare meglio lambdas in Java 8 (che sono come chiusure ma un po 'diverse). – markspace

+2

[Differenza tra finale ed efficacemente finale] (http://stackoverflow.com/questions/20938095/difference-between-final-and-effectively-final) – alex

risposta

7

In Java 7 il concetto di efficacemente finale stato introdotto per sostenere il "more precise rethrow" feature, e la sua portata è stata ampliata in Java 8 a coprire variabili locali che vengono definiti solo una volta, ma in realtà non dichiarato final. Questi possono essere acquisiti e utilizzato nei corpi lambda o classi interne proprio come se fossero dichiarati final.

Questo è trattato nel section §4.12.4 dei Java Language Specification:

Alcune variabili che non sono dichiarati 0.123.può invece essere considerato effettivamente finale.

Una variabile locale o un metodo, costruttore, lambda, o eccezione parametro è efficacemente finale se non è dichiarato final ma non avviene come operando mano sinistra di un operatore di assegnazione (§15.26) o come l'operando di un incremento prefisso o postfisso o operatore di decremento (§15.14, §15.15).

Inoltre, una variabile locale la cui dichiarazione manca un inizializzatore è efficacemente finale se tutte le seguenti sono vere:

  • Non è dichiarato final.

  • Ogni volta che si presenta come l'operando di sinistra di un incarico operatore, è sicuramente non assegnato e non assegnato in modo definitivo a prima dell'assegnazione; ovvero, è sicuramente non assegnato e non è assegnato allo definitivamente dopo l'operando di destra dell'assegnazione (§16 (Definite Assignment)).

  • Non si verifica mai come l'operando di un incremento prefisso o suffisso o operatore decremento.

Se una variabile è effettivamente finale, aggiungendo il modificatore final alla sua dichiarazione non introdurrà gli eventuali errori di compilazione.Viceversa, una variabile locale o parametro in un programma valido diventa definitivamente definitiva se il modificatore final viene rimosso.

+3

In realtà, la nozione di * effective final * è stata aggiunta in Java 7, e utilizzato nella funzione "rethrow più preciso". Il suo scopo è stato ampliato in Java 8 per coprire le variabili locali catturate da lambda o classi interne. –

+1

Grazie, @ Brian! Ho aggiornato la mia risposta per riflettere questo. –

3

E 'ancora la stessa regola, tranne il compilatore non ti costringe a definire esplicitamente la variabile come final più. Se è efficacemente finale, è possibile accedervi. Se non lo è (cioè il compilatore rileva che la variabile è riassegnata), quindi non viene compilata.

Problemi correlati