web-dev-qa-db-fra.com

Comment passer des paramètres à une classe anonyme?

Est-il possible de passer des paramètres ou d'accéder à des paramètres externes à une classe anonyme? Par exemple:

int myVariable = 1;

myButton.addActionListener(new ActionListener() {
    public void actionPerformed(ActionEvent e) {
        // How would one access myVariable here?
    }
});

Existe-t-il un moyen permettant à l'auditeur d'accéder à myVariable ou de recevoir myVariable sans créer l'auditeur en tant que classe nommée?

142
Lewis

Techniquement, non, car les classes anonymes ne peuvent pas avoir de constructeur.

Cependant, les classes peuvent référencer des variables à partir de portées. Pour une classe anonyme, il peut s'agir de variables d'instance de la ou des classes contenant ou de variables locales marquées comme finales.

edit: Comme Peter l’a souligné, vous pouvez également passer des paramètres au constructeur de la superclasse de la classe anonyme.

76
Matthew Willis

Oui, en ajoutant une méthode d'initialisation qui retourne 'this' et en appelant immédiatement cette méthode:

int myVariable = 1;

myButton.addActionListener(new ActionListener() {
    private int anonVar;
    public void actionPerformed(ActionEvent e) {
        // How would one access myVariable here?
        // It's now here:
        System.out.println("Initialized with value: " + anonVar);
    }
    private ActionListener init(int var){
        anonVar = var;
        return this;
    }
}.init(myVariable)  );

Aucune déclaration "finale" nécessaire.

328
Adam Mlodzinski

oui. vous pouvez capturer variable, visible pour la classe interne. la seule limitation est qu'il doit être final

27
aav

Comme ça:

final int myVariable = 1;

myButton.addActionListener(new ActionListener() {
    public void actionPerformed(ActionEvent e) {
        // Now you can access it alright.
    }
});
20
adarshr

Cela fera la magie

int myVariable = 1;

myButton.addActionListener(new ActionListener() {

    int myVariable;

    public void actionPerformed(ActionEvent e) {
        // myVariable ...
    }

    public ActionListener setParams(int myVariable) {

        this.myVariable = myVariable;

        return this;
    }
}.setParams(myVariable));
13
user3510955

Comme indiqué à l'adresse http://www.coderanch.com/t/567294/Java/java/declare-constructor-anonymous-class , vous pouvez ajouter un initialiseur d'instance. C'est un bloc qui n'a pas de nom et qui est exécuté en premier (comme un constructeur).

On dirait qu'ils sont aussi discutés à Pourquoi Java Initialisateurs d'instance? et Comment un initialiseur d'instance est-il différent d'un constructeur? discute des différences entre constructeurs.

8
Rob Russell

Ma solution consiste à utiliser une méthode qui renvoie la classe anonyme implémentée. Des arguments normaux peuvent être transmis à la méthode et sont disponibles dans la classe anonyme.

Par exemple: (à partir de code GWT permettant de gérer un changement de zone de texte):

/* Regular method. Returns the required interface/abstract/class
   Arguments are defined as final */
private ChangeHandler newNameChangeHandler(final String axisId, final Logger logger) {

    // Return a new anonymous class
    return new ChangeHandler() {
        public void onChange(ChangeEvent event) {
            // Access method scope variables           
            logger.fine(axisId)
        }
     };
}

Pour cet exemple, la nouvelle méthode de classe anonyme serait référencée avec:

textBox.addChangeHandler(newNameChangeHandler(myAxisName, myLogger))

OU , en utilisant les exigences du PO:

private ActionListener newActionListener(final int aVariable) {
    return new ActionListener() {
        public void actionPerformed(ActionEvent e) {
            System.out.println("Your variable is: " + aVariable);
        }
    };
}
...
int myVariable = 1;
newActionListener(myVariable);
7
Alastair McCormack

D'autres personnes ont déjà répondu que les classes anonymes ne peuvent accéder qu'aux variables finales. Mais ils laissent ouverte la question de savoir comment garder la variable initiale non finale. Adam Mlodzinski a donné une solution mais elle est plutôt boursouflée. Il existe une solution beaucoup plus simple au problème:

Si vous ne voulez pas que myVariable soit final, vous devez l'envelopper dans une nouvelle portée où ce n'est pas grave, si c'est final.

int myVariable = 1;

{
    final int anonVar = myVariable;

    myButton.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
            // How would one access myVariable here?
            // Use anonVar instead of myVariable
        }
    });
}

Adam Mlodzinski ne fait pas autre chose dans sa réponse, mais avec beaucoup plus de code.

3
ceving

Vous pouvez utiliser plain lambdas ("les expressions lambda peuvent capturer des variables")

int myVariable = 1;
ActionListener al = ae->System.out.println(myVariable);
myButton.addActionListener( al );

ou même une fonction

Function<Integer,ActionListener> printInt = 
    intvar -> ae -> System.out.println(intvar);

int myVariable = 1;
myButton.addActionListener( printInt.apply(myVariable) );

Utiliser Function est un excellent moyen de refactoriser les décorateurs et les adaptateurs, voir ici

Je viens tout juste de commencer à apprendre sur les lambdas, alors si vous remarquez une erreur, n'hésitez pas à écrire un commentaire.

3
ZiglioUK

Un moyen simple de mettre de la valeur dans une variable externe (qui n’appartient pas à la classe anonymus) est la suivante:

De la même manière, si vous voulez obtenir la valeur d’une variable externe, vous pouvez créer une méthode qui retourne ce que vous voulez!

public class Example{

    private TypeParameter parameter;

    private void setMethod(TypeParameter parameter){

        this.parameter = parameter;

    }

    //...
    //into the anonymus class
    new AnonymusClass(){

        final TypeParameter parameterFinal = something;
        //you can call setMethod(TypeParameter parameter) here and pass the
        //parameterFinal
        setMethod(parameterFinal); 

        //now the variable out the class anonymus has the value of
        //of parameterFinal

    });

 }
1
heronsanches