245 votes

Dans un mode de réalisation non limitatif, l'image du véhicule est définie en fonction d'un modèle de véhicule.

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:

Je reçois 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);
}

196voto

Jesper Points 65733

Java ne supporte pas vrai fermetures, même si l'utilisation d'une classe anonyme comme vous utilisez ici (nouvelle TimerTask() { ... }) ressemble à une sorte de fermeture.

edit - 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 la méthode main() retourne.

Lorsque la méthode main() renvoie, les variables locales (comme lastPrice et prix) sera nettoyé de la pile, de sorte qu'ils n'existent plus après le main (), qui 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 et prix final, ils ne sont pas vraiment des variables, mais des constantes. Le compilateur peut alors il suffit de remplacer l'utilisation de lastPrice et prix 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:

public static void main(String args[]) {
    int period = 2000;
    int delay = 2000;

    Timer timer = new Timer();

    timer.scheduleAtFixedRate(new TimerTask() {
        // Variables as member variables instead of local variables in main()
        private double lastPrice = 0;
        private Price priceObject = new Price();
        private double price = 0;

        public void run() {
            price = priceObject.getNextPrice(lastPrice);
            System.out.println();
            lastPrice = price;
        }
    }, delay, period);      
}

31voto

Chris Chilvers Points 3882

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.

public class Foo
{
    private PriceObject priceObject;
    private double lastPrice;
    private double price;

    public Foo(PriceObject priceObject)
    {
        this.priceObject = priceObject;
    }

    public void tick()
    {
        price = priceObject.getNextPrice(lastPrice);
        lastPrice = price;
    }
}

maintenant, il suffit de créer un nouveau Foo comme définitive et d'appel .tick du timer.

public static void main(String args[]){
    int period = 2000;
    int delay = 2000;

    Price priceObject = new Price();
    final Foo foo = new Foo(priceObject);

    Timer timer = new Timer();
    timer.scheduleAtFixedRate(new TimerTask() {
        public void run() {
        foo.tick();
        }
    }, delay, period);
}

18voto

Robin Points 15032

Vous pouvez uniquement accéder aux finales 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 les prix de la variable qui est de la déclarer comme

final double lastPrice[1];
final double price[1];

et dans votre classe anonyme vous pouvez définir la valeur comme ceci

price[0] = priceObject.getNextPrice(lastPrice[0]);
System.out.println();
lastPrice[0] = price[0];

13voto

Peter Cardona Points 1109

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:

public class foo
{
    static class priceInfo
    {
    	public double lastPrice = 0;
    	public double price = 0;
    	public Price priceObject = new Price ();
    }

    public static void main ( String args[] )
    {

    	int period = 2000;
    	int delay = 2000;

    	final priceInfo pi = new priceInfo ();
    	Timer timer = new Timer ();

    	timer.scheduleAtFixedRate ( new TimerTask ()
    	{
    		public void run ()
    		{
    			pi.price = pi.priceObject.getNextPrice ( pi.lastPrice );
    			System.out.println ();
    			pi.lastPrice = pi.price;

    		}
    	}, delay, period );
    }
}

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.

7voto

Buhb Points 3110

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:

public class PriceData {
    	private double lastPrice = 0;
    	private double price = 0;

    	public void setlastPrice(double lastPrice) {
    		this.lastPrice = lastPrice;
    	}

    	public double getLastPrice() {
    		return lastPrice;
    	}

    	public void setPrice(double price) {
    		this.price = price;
    	}

    	public double getPrice() {
    		return price;
    	}
    }

    public class PriceTimerTask extends TimerTask {
    	private PriceData priceData;
    	private Price priceObject;

    	public PriceTimerTask(PriceData priceData, Price priceObject) {
    		this.priceData = priceData;
    		this.priceObject = priceObject;
    	}

    	public void run() {
    		priceData.setPrice(priceObject.getNextPrice(lastPrice));
    		System.out.println();
    		priceData.setLastPrice(priceData.getPrice());

    	}
    }

    public static void main(String args[]) {

    	int period = 2000;
    	int delay = 2000;

    	PriceData priceData = new PriceData();
    	Price priceObject = new Price();

    	Timer timer = new Timer();

    	timer.scheduleAtFixedRate(new PriceTimerTask(priceData, priceObject), delay, period);
    }

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X