Search code examples
javaactionlistenerinner-classesfinalanonymous-inner-class

Trying to add ActionListener to a buttonArray


I am not exactly sure what is wrong with my code but, in the process of adding the ActionListeners, I get the error : "local variables referenced from an inner class must be final or effectively final." Appreciate the help :).

for (int i = 0; i < 30; i++) {
        button[i].addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent ae) {
                if (ae.getSource() == button[i]) {
                    if (game.panel[i] instanceof Treasure || game.panel[i] instanceof Mine) {
                        game.incScore(game.referTile(i));
                        if (game.panel[i] instanceof Treasure) {
                            treasurelocated++;
                            //Output onto jta
                            if (treasurelocated == 4) {
                                GEnd();
                            }
                        } else {
                            //Output onto jta found mine
                        }
                    } else {
                        //Output onto jta found nothing
                        game.blank();
                    }
                    changeS();
                    button[i].setEnabled(false);
                }
            }
        });
    }

Solution

  • Just after the new ActionLister() { you start defining an anonymous inner class. It's a "no-name" class implementing the ActionListener interface. The code which follows is enclosed in the context of this inner class and must follow special rules.

    The Java language specification requires that

    local variables referenced from an inner class must be final or effectively final.

    A final variable is a variable marked with the final keyword. Such a variable may be assigned only once, it's virtually a constant.

    An effectively final variable is such a variable, where adding the final keyword does not cause the compiler to complain. In other words, it is effectively final, but just not marked with the proper keyword.

    Now back to your code. One or more variables in your code is a local variable from the method enclosing your code which is neither final nor effectively final.

    Specially, your variable i is one of them for sure. You should not refer to button[i] from the code of the listener. Actually, you do not need it! It is guaranteed that the listener is always called on just the button the event happened on. If you need a reference to game.panel[i], put it somehow to your button (e.g. as a reference).

    For more explanation, read my answer here: https://stackoverflow.com/a/24170806/2886891. From there you may learn more about the context of the listener's code. Remember: the code of the listener is called within completely different context than where it is defined, so the i variable does not have the meaning you would expect.