Search code examples
javaasynchronousscopestaticfinal

cheat with java final keyword


I'm writing some java code and at one moment I was blocked at one thing.

final String action = "action1";
final Button otherAction = (findById....);
otherAction.setOnClickListener(new View.OnClickListener() {
    @Override
        public void onClick(View v) {
            if (action.equals("action1")) {
                action = "action2";
            } else if (action.equals("action2")) {
                action = "action3";
            } else if (action.equals("action3")) {
                action = "action1";
            }
        }
    });

Obviously this code doesn't work because I can't assign a new value to action, because it's a final variable and so can only be initialized one time.
And to access a variable from inside the onClickListener scope, you must declare it final.

So what I did to fix that is:

final Button otherAction = (findById....);
otherAction.setOnClickListener(new View.OnClickListener() {
    @Override
        public void onClick(View v) {
            if (t.action.equals("action1")) {
                t.action = "action2";
            } else if (t.action.equals("action2")) {
                t.action = "action3";
            } else if (t.action.equals("action3")) {
                t.action = "action1";
            }
        }
    });

Class t {
    public static String action = "action1";
}

My question is: Why is this working?


Solution

  • Fields don't have to be final to be accessed from anonymous classes, just method variables.

    This is because field (of its entity or class) exists until it is no longer needed (determined by GC), so there's always a place where you can assign.

    However, if you're passing anonymous class instance somewhere, it might still exist when containing method has exited. Imagine otherAction invoking this listener sowetime in distant future. But there's nowhere to assign this variable anymore, hence it should be final and copied on anynomous class instantiation.