2010-09-07 2 views
2

J'ai rencontré un comportement étrange dans l'affectation des variables finales. Vous pouvez assigner une variable finale dans un constructeur pour l'initialiser, ce qui est logique. Cependant, vous ne pouvez pas faire la même chose dans une sous-classe, même si la dernière variable est membre de la sous-classe -Règles d'attribution impair pour Java final

public class FinalTest { 
    public final String name; 

    public FinalTest() 
    { 
     name = "FinalTest"; 
    } 

    public static class FinalTestSubclass extends FinalTest { 
     public FinalTestSubclass() 
     { 
      name = "FinalTestSubclass"; //<---- this won't compile, assignment to final variable. 
     } 
    } 
} 

Quelqu'un peut-il penser à une bonne raison pour que cela/fonctionnerait de cette façon?

+0

Peu importe, la réaffectation dans le 2ème constructeur, ne l'a pas vu. –

Répondre

11

Chaque constructeur d'une sous-classe doit appeler un constructeur de la superclasse sa première opération. Chaque variable membre finale doit être initialisée avant la fin d'un constructeur. Une dernière variable ne peut être affectée qu'une seule fois. Compte tenu de ces règles, il est impossible pour un constructeur de sous-classe d'attribuer directement une valeur à un membre de la superclasse final. Faire des exceptions augmenterait la complexité et créerait des "gotchas" en échange d'un utilitaire additionnel limité.

Une solution pratique consiste à fournir un constructeur de superclasse qui prend une valeur à attribuer au membre final. Cela peut être protected ou paquet-privé si désiré. Si la superclasse est en dehors de votre contrôle, il y a de fortes chances que permettre aux classes dérivées de casser ses hypothèses sur la finalité de ses membres causerait d'autres problèmes.

6

Si vous étiez autorisé à affecter une valeur à name dans FinalTestSubClass cela signifierait que la valeur affectée dans FinalTest n'était pas réellement la valeur finale.

Si votre exemple était valide, cela signifierait que name pourrait avoir des valeurs différentes (selon la classe instanciée), rendant le modificateur final assez redondant.

Une meilleure question est, pourquoi devrait le comportement que vous désirez être autorisé?

+1

En fait, pour une instance de FinalTestSubclass, le champ aurait des valeurs différentes à des moments différents: il recevrait d'abord "FinalTest" dans le constructeur de super classe, puis "FinalTestSubclass" dans le constructeur de la sous-classe. – meriton

+0

Addendum: Il est parfaitement acceptable qu'un champ final non statique ait des valeurs différentes dans différents objets. – meriton

3

informellement, les champs finaux devraient avoir été initialisés lorsque le constructeur est fini. Dans le constructeur de votre sous-classe, super() a été appelé implicitement, le constructeur de la super classe est terminé, les derniers champs de la super classe ne doivent pas être modifiés.

vous voudrez peut-être ceci:

class A 
    final String s; 
    A(String s){ this.s = s; } 
    A() { this("default"); } 

class B extends A 
    B(){ super("B's default"); } 
1

Ce comportement est standard dans Java

Le mot clé peut finale utilisée de manière multiple, pour la classe fermer la possibilité de inherite de celui-ci, pour la méthode pour le surcharger, pour les variables ne permettent d'être affectés qu'une seule fois en mots simples.

Pour votre cas, cette variable est allready attribué en super classe,

ce que vous pouvez faire est

public class FinalTest { 
    public final String name = "FinalTest"; 

    public FinalTest() 
    { 

    } 

    public static class FinalTestSubclass extends FinalTest { 

     public final String name = "FinalTestSubclass"; 

     public FinalTestSubclass() 
     { 

     } 
    } 
} 

Read more about final variables

0

En réponse à votre commentaire à la réponse de matt; vous pouvez obtenir la détermination de la constante dans la sous-classe en la passant dans le constructeur:

public class FinalTest { 
    public final String name; 

    public FinalTest() 
    { 
     this("FinalTest"); 
    } 

    protected FinalTest(String nameConstant) 
    { 
     name = nameConstant; 
    } 

    public static class FinalTestSubclass extends FinalTest { 
     public FinalTestSubclass() 
     { 
      super("FinalTestSubclass"); 
     } 
    } 
}