Ne peut pas se référer à un non-finale de la variable à l'intérieur d'un intérieur classe définie dans une méthode différente
Modifié:
J'ai besoin de changer les valeurs de plusieurs variables, comme ils courent à plusieurs reprises par une minuterie. J'ai besoin de continuer à mettre à jour les valeurs à chaque itération de la minuterie. Je ne peux pas définir les valeurs à la finale comme qui va m'empêcher de mettre à jour les valeurs que j'obtiens l'erreur que je décris dans la première question ci-dessous:
J'avais déjà écrit ce qui est ci-dessous:
J'obtiens le message d'erreur "ne peut pas se référer à un non-finale de la variable à l'intérieur d'un intérieur classe définie dans une méthode différente".
Ce qui se passe pour le double du prix de vente et le Prix priceObject. Savez-vous pourquoi je reçois ce problème. Je ne comprends pas pourquoi j'ai besoin d'une déclaration finale. Aussi, si vous pouvez voir ce que c'est je suis en train de faire, que dois-je faire pour contourner ce problème.
public static void main(String args[]) {
int period = 2000;
int delay = 2000;
double lastPrice = 0;
Price priceObject = new Price();
double price = 0;
Timer timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
public void run() {
price = priceObject.getNextPrice(lastPrice);
System.out.println();
lastPrice = price;
}
}, delay, period);
}
la réponse est simple: "Non". Mais vous pouvez obtenir l'effet désiré, à l'aide d'un intérieur de classe; voir @petercardona de réponse.
OriginalL'auteur Ankur | 2009-08-19
Vous devez vous connecter pour publier un commentaire.
Java ne supporte pas vrai fermetures, même si l'utilisation d'une classe anonyme comme vous utilisez ici (
new TimerTask() { ... }
) ressemble à une sorte de fermeture.modifier - Voir les commentaires ci-dessous - ci-dessous n'est pas une bonne explication, comme KeeperOfTheSoul points.
C'est pourquoi il ne fonctionne pas:
Les variables
lastPrice
et les prix sont variables locales de la méthode main (). L'objet que vous créez avec la classe anonyme pourrait durer jusqu'à ce que après lamain()
méthode retourne.Lorsque le
main()
méthode retourne, les variables locales (commelastPrice
etprice
) sera nettoyé de la pile, de sorte qu'ils n'existent plus aprèsmain()
retourne.Mais la classe anonyme références de l'objet de ces variables. Les choses tournent mal si la classe anonyme objet tente d'accéder à des variables après qu'ils ont été nettoyés.
En faisant
lastPrice
etprice
final
, ils ne sont pas vraiment des variables, mais des constantes. Le compilateur peut alors il suffit de remplacer l'utilisation delastPrice
etprice
dans la classe anonyme avec les valeurs des constantes (au moment de la compilation, bien sûr), et vous n'aurez pas le problème à l'accès inexistantes des variables plus.D'autres langages de programmation qui ne soutien de fermetures de le faire par le traitement de ces variables spécialement en rendant sûr de ne pas être détruit lorsque la méthode se termine, ainsi que la fermeture peut toujours accéder aux variables.
@Maumau: Vous pourriez faire ceci:
Ce n'est pas un "drôle d'effet de bord", c'est le comportement normal de personnes attendez - et Java ne peut pas délivrer de parce que il ne génère pas de capture. Comme solution de contournement, les variables locales utilisées dans une classe anonyme doit être définitive.
Jesper, vous devrez probablement modifier les mauvaises pièces de vos réponses, plutôt que de simplement avoir un message disant que le ci-dessus est incorrecte.
Java n'est pas, en fait, le soutien des fermetures. Les langues qui prennent en charge les fermetures de le faire par le stockage de la totalité de l'environnement local (c'est-à-dire le jeu de variables locales définies dans le courant de la stack frame) comme un tas d'objet. Java n'a pas de support pour ce (la langue concepteurs ont voulu mettre en œuvre, mais a manqué de temps), donc comme une solution de contournement, lorsqu'une classe est instanciée, les valeurs des variables locales à qui il se réfère sont copiés sur le tas. Cependant, la JVM ne peut plus garder les valeurs en synchronisation avec les variables locales, c'est pourquoi ils doivent être final.
Cette réponse est totalement déroutant maintenant qu'il n'y a personne nommée "KeeperOfTheSoul" qui a commenté. La réponse devrait être révisée.
OriginalL'auteur Jesper
Pour éviter des effets secondaires bizarres avec des fermetures en java les variables référencées par un anonyme, un délégué doit être marqué en finale, donc à vous référer à
lastPrice
et des prix dans la minuterie de la tâche qu'ils ont besoin d'être marqué comme final.De toute évidence, cela ne fonctionnera pas pour vous parce que vous souhaitez les modifier, dans ce cas, vous devriez regarder les encapsulant dans une classe.
maintenant, il suffit de créer un nouveau Foo comme définitive et d'appel .tick du timer.
OriginalL'auteur Chris Chilvers
Vous ne pouvez accéder finale des variables à partir de la classe conteneur lors de l'utilisation d'une classe anonyme. Par conséquent, vous avez besoin de déclarer les variables utilisées final (qui n'est pas une option pour vous, puisque vous êtes l'évolution lastPrice et prix), ou de ne pas utiliser une classe anonyme.
Afin que vos options sont à créer une réelle intérieur de la classe, dans laquelle vous pouvez passer dans les variables et les utiliser dans un mode normal
ou:
Il est rapide (et à mon avis laid) hack pour votre lastPrice et prix variable qui est de la déclarer comme
et dans votre classe anonyme, vous pouvez définir la valeur comme cela
+1
pour un Génie!!!OriginalL'auteur Robin
De bonnes explications pour expliquer pourquoi vous ne pouvez pas faire ce que vous essayez de faire déjà fourni. Comme une solution, peut-être envisager:
Semble probablement que vous pourriez faire un meilleur design que cela, mais l'idée est que vous pouvez regrouper les mises à jour des variables à l'intérieur d'une classe de référence qui ne change pas.
OriginalL'auteur Peter Cardona
Avec anonyme classes, vous êtes en fait la déclaration d'une "nameless" classe imbriquée. Pour les classes imbriquées, le compilateur génère un nouveau public autonome de la classe avec un constructeur qui prendra toutes les variables qu'il utilise comme arguments (pour le "nommé" classes imbriquées, c'est toujours une instance de l'original/classe englobante). Ceci est fait parce que l'environnement d'exécution n'a aucune notion de classes imbriquées, donc il doit y avoir un (automatique), la conversion d'une imbriquées à une classe autonome.
Prendre ce code par exemple:
Qui ne fonctionnent pas, parce que c'est ce que le compilateur n'sous le capot:
L'original de la classe anonyme est remplacée par la classe autonome que le compilateur génère (code n'est pas exact, mais devrait vous donner une bonne idée):
Comme vous pouvez le voir, la classe autonome contient une référence à l'objet partagé, rappelez-vous que tout dans java est passé par valeur, de sorte que même si la variable de référence "partagée" dans EnclosingClass est changé, l'instance, il est pas modifié, et toutes les autres variables de référence vers celui-ci (comme celui de la classe anonyme: en Joignant$1), ne seront pas conscients de cela. C'est la principale raison pour que le compilateur vous oblige à déclarer ce "partagée" de variables, comme la finale, de sorte que ce type de comportement ne va pas dans votre déjà en cours d'exécution de code.
Maintenant, c'est ce qui arrive lorsque vous utilisez une variable d'instance, à l'intérieur d'une classe anonyme (c'est ce que vous devez faire pour résoudre votre problème, déplacez votre logique pour un "exemple" méthode ou d'un constructeur d'une classe):
Cette compile bien, parce que le compilateur va modifier le code, de sorte que la nouvelle classe générée en Joignant$1 contiendra une référence à l'instance de EnclosingClass où il a été instancié (ce n'est qu'une représentation, mais devrait vous aller à):
Comme ça, quand la variable de référence "partagée" dans EnclosingClass obtient réaffectés, et ce qui se passe avant l'appel à la Thread#run(), vous verrez des "autres bonjour" imprimé deux fois, parce que maintenant EnclosingClass$1#joignant la variable de conserver une référence à l'objet de la classe où elle est déclarée, de sorte que des modifications à n'importe quel attribut sur cet objet sera visible par les instances de EnclosingClass$1.
Pour plus d'informations sur le sujet, vous pouvez voir cet excellent blog (pas écrit par moi): http://kevinboone.net/java_inner.html
Que faire si la variable locale "partagée" est un objet mutable? Selon votre explication en déclarant "final" n'aide pas non plus, à droite?
Déclarant "partagé" comme final vous permettra de modifier l'état de l'objet de la dernière variable de références, mais pour cet exemple particulier qui ne fonctionne pas parce que vous ne serez pas en mesure de modifier la valeur de la "partagé" de la variable (qui est ce que l'OP voulait), vous serez en mesure d'utiliser à l'intérieur de classes anonymes, mais sa valeur ne change pas (parce qu'elle est déclarée final). Il est important de noter la différence entre les variables et les valeurs qu'ils détiennent (qui peuvent être primitives ou des références à des objets dans le tas).
>>> mais sa valeur ne change pas je suppose que vous êtes absent le point de savoir si la dernière variable de référence pointe vers un objet mutable il peut encore être mis à jour, cependant, la classe anonyme crée la copie superficielle ainsi, les changements sont reflétés dans la classe anonyme. En d'autres termes, l'état de la synchronisation qui est ce qui est recherché ici. Ici, OP besoins en capacité de modifier la variable partagée (le type primitif) et, pour y parvenir, OP devez envelopper la valeur sous une mutable objet et l'a partagé mutable objet.
Bien sûr, l'OP peut envelopper la valeur nécessaire en vertu d'un objet mutable, déclarer la variable comme définitive et l'utiliser à la place. Cependant, il peut éviter d'utiliser un objet supplémentaire en déclarant la variable comme un attribut de la classe en cours (comme indiqué et expliqué dans la réponse). Forcer mutable objets (comme l'utilisation de matrices juste pour être en mesure de modifier la valeur d'une variable partagée) n'est pas une bonne idée.
OriginalL'auteur emerino
Quand je tombe sur ce problème, je viens de passer les objets à l'intérieur de la classe par le constructeur. Si j'ai besoin de passer des primitives ou des objets immuables (comme dans ce cas), une classe wrapper est nécessaire.
Edit: en Fait, je n'utilise pas une classe anonyme à tous, mais une bonne sous-classe:
OriginalL'auteur Buhb
Vous ne peut pas se référer à des non-final des variables Java Language Specification dit. De 8.1.3:
"Toute variable locale de la méthode officiel paramètre ou gestionnaire d'exception paramètre utilisé, mais non déclarée dans un intérieur de classe doit être déclarée final." Paragraphe entier.
Je ne peux voir qu'une partie de votre code - selon moi, la planification de la modification des variables locales est une idée étrange. Les variables locales cessent d'exister lorsque vous quittez la fonction. Peut-être que les champs statiques d'une classe serait mieux?
OriginalL'auteur Tadeusz Kopec
Je viens d'écrire quelque chose à poignée quelque chose le long de la auteurs intention.
J'ai trouvé la meilleure chose à faire était de laisser le constructeur de prendre tous les objets, puis dans votre méthode mise en œuvre par l'utilisation que constructeur d'objets.
Toutefois, si vous écrivez une interface générique de la classe, alors vous avez à passer un Objet, ou mieux une liste d'Objets. Cela pourrait être fait par l'Objet[] ou encore mieux, Objet ... parce qu'il est plus facile d'appeler.
Voir mon exemple pièce juste en dessous.
Veuillez voir ce post sur Java fermetures qui prend en charge ce de la boîte:
http://mseifed.blogspot.se/2012/09/closure-implementation-for-java-5-6-and.html
Version 1 permet le passage de la non-final fermetures avec autocasting:
https://github.com/MSeifeddo/Closure-implementation-for-Java-5-6-and-7/blob/master/org/mo/closure/v1/Closure.java
OriginalL'auteur momomo
Si vous voulez modifier une valeur dans un appel de méthode dans une classe anonyme, que la "valeur" est en fait un
Future
. Donc, si vous utilisez la Goyave, vous pouvez écrireOriginalL'auteur Earth Engine
Une solution que j'ai remarqué, n'est pas mentionné (à moins que j'ai raté ça, si je l'ai fait s'il vous plaît corrigez-moi), est l'utilisation d'une variable de classe. Couru dans ce numéro tente de lancer un nouveau thread dans une méthode:
new Thread(){ Do Something }
.Appel
doSomething()
de ce qui suit fonctionnera. Vous n'avez pas nécessairement à les déclarerfinal
, juste besoin de changer la portée de la variable de sorte qu'il n'est pas perçu avant la innerclass. C'est moins bien sûr de votre processus est énorme et la modification de la portée pourrait créer une sorte de conflit. Je n'ai pas voulu faire ma variable final tel qu'il était en aucune façon un final/constant.OriginalL'auteur James
Si la variable doivent être définitif, ne peut être alors que vous pouvez affecter la valeur de la variable à une autre variable, et QUE le final de sorte que vous pouvez l'utiliser à la place.
OriginalL'auteur Thorbjørn Ravn Andersen
l'utilisation d'un nom de Classe.c'.variableName pour faire référence à la finale de la variable
OriginalL'auteur user3251651
vous pouvez simplement déclarer la variable en dehors de l'extérieur de la classe. Après cela, vous serez en mesure de modifier la variable à partir à l'intérieur de la classe. J'ai parfois confrontés à des problèmes similaires lors de l'encodage dans android, donc je déclare la variable comme globale et cela fonctionne pour moi.
OriginalL'auteur Abhijay Ghildyal
Pouvez-vous faire
lastPrice
,priceObject
, etprice
champs de l'anonyme intérieur de la classe?OriginalL'auteur Greg Mattes
La principale préoccupation est de savoir si une variable à l'intérieur de la classe anonyme instance peut être résolu au moment de l'exécution. Ce n'est pas une nécessité pour rendre une variable final aussi longtemps que il est garanti que la variable est à l'intérieur de la portée. Par exemple, voir les deux variables _statusMessage et _statusTextView à l'intérieur de updateStatus() la méthode.
OriginalL'auteur WaiKit Kung
ce qui a fonctionné pour moi est simplement de définir la variable en dehors de cette fonction de votre.
Juste avant la fonction principale déclarer, c'est à dire
OriginalL'auteur punkck
Déclarer la variable comme statique et la référence dans la méthode requise à l'aide d'un nom de classe.variable
Non-static parameter cannot be referenced from a static context
les variables locales et les paramètres de la méthode ne peut pas être déclaré "statique", c'est d'ailleurs, à propos de la façon dont il a été mis en place pour permettre des classes dans les méthodes locales (anonyme classes), de poursuivre l'accès aux variables locales et les paramètres de la méthode, même après la méthode a repris il porte leur "finale" des copies et les utilise comme variables d'instance.
OriginalL'auteur shweta
Juste une autre explication. Considérons cet exemple ci-dessous
Ici la Sortie sera
m1 Complète
Thread t exécute
Thread t exécute
Thread t exécute
................
Maintenant la méthode m1() se termine et nous affecter de référence variable o'null , Maintenant Extérieur de la Classe d'Objet est admissible pour le GC, mais à l'Intérieur de la Classe de l'Objet est toujours exister et qui a (A-A) en relation avec l'objet Thread qui est en cours d'exécution. Sans Externe existante objet de classe il n'y a aucune chance de l'existant m1() la méthode et sans existantes m1() la méthode il n'y a aucune chance de l'existant, sa variable locale, mais si l'Intérieur de la Classe de l'Objet utilise la variable locale de m1() méthode, puis tout est auto-explicatif.
Pour résoudre cela, nous devons créer une copie de la variable locale et de copier ensuite dans le tas à l'Intérieur de la classe de l'objet, ce que java n'a pour seule variable finale parce qu'ils ne sont pas réellement variable, ils sont comme des constantes(Tout ce qui se passe au moment de la compilation, pas seulement au moment de l'exécution).
OriginalL'auteur pks
Pour résoudre le problème ci-dessus, les différentes langues des décisions différentes.
pour Java, la solution est aussi ce que nous verrons dans cet article.
pour C#, la solution est de permettre à des effets secondaires et la capture par référence est la seule option.
pour le C++11, la solution est de permettre au programmeur de prendre la décision. Ils peuvent choisir de capturer par valeur ou par référence. Si la capture de la valeur, pas d'effets secondaires pourraient se produire parce que la variable référencée est en fait différent. Si la capture par référence, les effets secondaires peuvent se produire, mais le programmeur doit s'en rendre compte.
OriginalL'auteur Earth Engine
Parce que c'est source de confusion si la variable n'est pas définitive, car le changement ne sera pas ramassé dans la classe anonyme.
Juste faire les variables "prix" et " lastPrice finale.
-- Edit
Oups, et vous aurez aussi besoin de ne pas céder à eux, évidemment, dans votre fonction. Vous aurez besoin de nouvelles variables locales. De toute façon, je soupçonne quelqu'un vous a donné une meilleure réponse maintenant.
Mais alors, comment puis-je modifier les valeurs quand j'en ai besoin?
Pas seulement parce que c'est source de confusion; c'est parce que Java ne supporte pas les fermetures. Voir ma réponse ci-dessous. @Maumau: Vous pourriez faire l'variables variables membres de la classe anonyme de l'objet plutôt que des variables locales dans main().
Il est en train de modifier, de sorte qu'ils ne peuvent pas être définitive.
Si le prix et lastPrice ont été finale de, les affectations à ne pas compiler.
OriginalL'auteur Noon Silk