Why is it not possible to modify local variables when accessed within anonymous classes?

Asked

Viewed 440 times

11

When trying to access a local variable from a method of an anonymous class in java, we usually get a syntax error if we try to modify its content. Some Fdis suggest that we turn the variable into final, thus, its content becomes immutable, but then the error changes, and becomes the attempt to access a content that cannot be changed.

However, if we only read its content, even not modifying to final, no error is presented and the code works normally, with the copy of the content being made without problems.

But when you create a class variable and try to access within the anonymous class, not only can you read its content, but it is also allowed to be changed, as can be seen in the example below:

public class AccessLevelVariableTest {

    private String oneVariable = "oneVariable";


    public void myMethod() {

        String localVariable = "localVariable";

        JButton btn = new JButton();

        btn.addActionListener(new ActionListener(){

            @Override
            public void actionPerformed(ActionEvent evt){

                oneVariable = localVariable; //isso é permitido
                System.out.println(localVariable); //isso é permitido
                localVariable = oneVariable; // isso ocorre erro de sinxate

            }
        });
    }
}

If the local variable is viewed by the anonymous class, I believe it is not a problem linked only to its scope, so what is the point of restricting access to a local variable in this way, different from the class variable? What kind of impact could such a change cause to have such a restriction?

  • 1

    ah, I think it would be much simpler to ask why a property or whatever, like protected or private cannot be directly referenced.

  • 1

    @Edilson but that’s not really my question, about access modifiers I’ve read right here on the site and understood. The doubt is about variables of even smaller scope.

  • 1

    Local variable being accessed for reading is allowed? I confess I never noticed it. I thought it was forbidden to read as well as write.

2 answers

9


Responding briefly - and I’m no expert on Java -, this is due to the way Java handles closures. What Java makes available to the anonymous class is not the variables themselves (i.e., references to certain values), but their values. Thus, if the variable is changed in the external scope, this will not be reflected in the anonymous class. In the same way, as if it has only one value unlinked from the original variable, it is not possible to change it - if the language allowed, this change would only have effect within the anonymous class, and this would be confusing.

Such functioning probably was a deliberate choice, to avoid the additional complexity that this would require of the compiler. C# works differently (with very similar syntax), because it made a different choice.

Source: Why are only final variables accessible in Anonymous class?, answer from Jon Skeet

  • I mean, it’s not closure :D

  • @bigown I thought the same. But the fact that Skeet used the term left me in doubt.

  • There are controversies about the exact definition, you have to say that it has to be the variable and there are those who say that just the state of it.

3

localVariable only exists during the execution of the method myMethod(). Since the created object can exist in the external scope of the method, the variable localVariable there will be no more.

  • If it doesn’t exist, how is its content accessible within the anonymous class? See the question code.

  • A final reference is maintained. As if it had become a final attribute within the anonymous class, like new run() { final String localVariableInterno = localVariable; [...]

  • Who voted negative can explain why. What is said in the answer is wrong?

  • I still don’t understand the rationale. Scope of the answer. If every time the anonymous class is executed and the value is used, it needs to exist, otherwise we would be working with a null value.

  • Remembering that the anonymous class is called in the same scope of the local variable, that is, it will only be executed when the same method is also executed.

  • 2

    Lembrando que a classe anônima é chamada no mesmo escopo da variavel local, No, it is not called in that scope. It is created and passed on. Potentially (not required in this example specific, but it is possible to general case), it can be executed on another thread, or it can be executed on an executor in a thread pool. You created the object and passed on, what happens next is not in the context of the method.

  • In the case of the example with Runnable, I understand that this can occur, but in the case of Liener, the scope is the same, so much so that by debugging, the method is locked until the execution of the anonymous class ends. I think the example with Runnable ended up generating this confusion. I will change the example.

  • @ramaral, I believe that who voted I have been the diegofm himself, because the answer had not been enough. Was it yourself, diegofm? If not, if it was someone else, you can confirm the negative?

  • In the case of any variable you do not have control. Imagine a AbstractFactory. The returned object will be consumed at another point outside her control. This is the general case I spoke of

  • @Jeffersonquesado can you demonstrate this in the answer? I’m really not getting the reasoning you’re following very well.

  • @diegofm In the case of Listener it is equal, at the time when the implementation method(anonymous class) is called, the method that created the class is no longer in scope. During the scope of the method only the class was created. Think of a system to click a button.

  • 2

    @Jeffersonquesado Try to improve your answers using the content of your comments.

  • @diegofm You yourself speak of the case of a class attribute, it does not need to be final. So, everything has to do with the variable scope.

  • @ramaral but if it were only a scope problem, arrays and lists would give the same problem, but when the local variable is list, it is allowed to change its content normally.

  • @diegofm?

  • @ramaral veja: https://ideone.com/KEQAtj

  • 1

    @diegofm It is final, Java 8 infers this. On the other hand you are not changing the variable, try to do localVariable = new ArrayList<>(); within actionPerformed() and see the error.

Show 12 more comments

Browser other questions tagged

You are not signed in. Login or sign up in order to post.