2013-08-14 4 views
4

Si j'avais cette méthode anonyme, je devrais déclarer x variable comme finale.Pourquoi les variables doivent être finales dans les méthodes anonymes et les champs de classe ne le font pas

private void testMethod (ListField<BeanModel> listField){ 

    final ListLoader<BeanModel> loader = new PagedListLoader<BeanModel>(); 
    listField.addListener(Events.Attach, new Listener<ListViewEvent<BeanModel>>() { 

      @Override 
      public void handleEvent(ListViewEvent<BeanModel> be) { 
       loader.load(); 
      } 
      }); 
} 

Cependant, si chargeur était un champ de classe, il ne serait pas nécessaire de le déclarer comme définitif:

public class testClass{ 

    private ListLoader<BeanModel> loader = new PagedListLoader<BeanModel>(); 

    private void testMethod (ListField<BeanModel> listField){ 
     listField.addListener(Events.Attach, new Listener<ListViewEvent<BeanModel>>() { 

        @Override 
        public void handleEvent(ListViewEvent<BeanModel> be) { 
         loader.load(); 
        } 
        }); 

     //Could I modify loader's reference here, before the method executes? 
     //loader = null; 
     } 
} 

Est-ce que quelqu'un sait la raison pour laquelle ils garantissent les variables locales de ne pas changer quand ils est accessible mais ne le fais pas pour les champs de classe?

+0

@jlordo. Pas exactement. Ce poste ne parle pas des champs, seulement des variables locales. –

+0

Le même principe s'applique.C'est une classe interne (anonyme) qui fait référence à l'instance de la classe externe et qui peut donc accéder à ses champs. – jlordo

+0

un autre ici http://stackoverflow.com/questions/1299837/cannot-refer-to-a-non-final-variable-inside-an-inner-class-defined-in-a-differen – kaos

Répondre

3

La variable locale est allouée dans la pile, et elle sortira de la portée après testMethod(). Faire la variable finale assure qu'il est correct de simplement passer une référence à la classe anonyme. Si ce n'était pas définitif, une affectation ultérieure dans testMethod() pourrait changer la valeur plus tard avec des résultats confus. (L'utilisateur peut s'attendre à la valeur affectée plus tard, mais ce serait impossible).

Un champ de la classe parente, toutefois, est accessible via la référence parente de la classe anonyme, de sorte que toutes les affectations ultérieures peuvent être traitées sans confusion.

+0

Mais, et si le contenu du champ a changé entre-temps? –

+0

@ AminAbu-Taleb Puisque l'accès passe par la référence parente, la classe interne peut toujours utiliser la dernière valeur. – kiheru

+0

C'est ce que je cherchais. –

1

Jetez un oeil à Lambda et Conjures en java.

Une classe interne anonyme n'a aucune information autour de lui - vous devez spécifier qu'elle est finale afin que vous puissiez garantir son existence.

Cela pourrait être quelque chose à voir avec la nature d'un ListLoader, mais je suis inexpérimenté avec l'aide de cette bibliothèque.

J'espère que je vous ai indiqué la bonne direction.

1

Les classes anonymes obtiennent implicitement des variables locales via les constructeurs. C'est qu'ils obtiennent des copies des vars locales qu'ils utilisent. Donc, si nous avons changé la valeur de la variable dans le code principal, la classe anonyme ne verrait pas cette modification. La déclaration des vars locaux finaux permet d'éviter cette ambiguïté.

8

Accroding java docs

Une classe anonyme a accès aux membres de sa classe englobante.
Une classe anonyme ne peut pas accéder à des variables locales dans son enfermant champ qui ne sont pas déclarés comme définitifs ou effectivement finale (efficacement finale signifie que la variable est jamais changé après son initialisation. Paramètres méthode sont souvent efficacement finale.)

Le La raison de cette restriction devient apparente si nous mettons en lumière la façon dont les classes locales sont mises en œuvre. Une classe locale anonyme peut utiliser des variables locales car le compilateur donne automatiquement à la classe un champ d'instance privée pour contenir une copie de chaque variable locale utilisée par la classe. Le compilateur ajoute également des paramètres cachés à chaque constructeur pour initialiser ces champs privés créés automatiquement. Ainsi, une classe locale n'accède pas réellement aux variables locales, mais simplement à ses propres copies privées. La seule façon de fonctionner correctement est que les variables locales soient déclarées définitives, de sorte qu'elles soient garanties de ne pas changer. Avec cette garantie en place, la classe locale est assurée que ses copies internes des variables reflètent avec précision les variables locales réelles.

+0

C'est ce que je ne comprends pas. Pourquoi veulent-ils garantir que les variables locales ne changent pas et ne le font pas dans les champs de classe? –

+0

Pensez à ce qui se passera si les variables locales tombent hors de la portée? Par exemple, supposons que vous ayez soumis quelques tâches futures en utilisant des variables locales pour démarrer après 2 heures et que la méthode actuelle soit terminée. Comment allez-vous revenir à ces valeurs d'origine comme ils sont partis de la pile? –

Questions connexes