2

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?

Sнаđошƒаӽ
  • 16,753
  • 12
  • 73
  • 90
Lucsartes
  • 321
  • 2
  • 13
  • 6
    for the simple reason - `t.action` is not final – Raman Shrivastava Apr 21 '16 at 09:14
  • 2
    anonymous inner classes can only access variables that are effectively final. It's been [explained in detail here](http://stackoverflow.com/questions/4732544/why-are-only-final-variables-accessible-in-anonymous-class) – CarefreeCrayon Apr 21 '16 at 09:21
  • 1
    @Raman Shrivastava Right, but I think the gist of the OP's question is why doesn't `t.action` need to be final when it is defined as a `public static` class variable while it has to be final when it is just a local variable. – Roland Krüger Apr 21 '16 at 09:22
  • You can make `action` an instance variable of your outer class. –  Apr 21 '16 at 09:41
  • I have seen "why is this not working?" questions, but this "Why is this working?" is probably the first of its kind. ;-) – Sнаđошƒаӽ Apr 21 '16 at 09:41
  • @a_horse_with_no_name => yes, i change this in my code thanks – Lucsartes Apr 21 '16 at 12:55

2 Answers2

3

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.

alamar
  • 18,729
  • 4
  • 64
  • 97
0

As I understand, the 1st code block doesn't work.The "work" here means: compilation error.

The 2nd works because if follows Java Language Specification. There was no restrictions on non-local parameter, formal parameter..The t.action is a static variable.

Any local variable, formal parameter, or exception parameter used but not declared in an inner class must be declared final.

Any local variable used but not declared in an inner class must be definitely assigned (§16) before the body of the inner class.

http://docs.oracle.com/javase/specs/jls/se7/html/jls-8.html#jls-8.1.3

One more note is that was before Java 8. Java 8 introduces the concept of: effective final which the local variables used for inner class like above don't need to be officially declared as final. For more detail, can see it at: https://docs.oracle.com/javase/specs/jls/se8/html/jls-8.html#jls-8.1.3

Any local variable, formal parameter, or exception parameter used but not declared in an inner class must either be declared final or be **effectively** final (§4.12.4), or a compile-time error occurs where the use is attempted.

See more explanation about effective-final here: Difference between final and effectively final

Regarding why the 2nd code block works, you can read here: Why are only final variables accessible in anonymous class?

It's provide the most reasonable answer about this problem I've ever seen :)

Community
  • 1
  • 1
NangSaigon
  • 1,253
  • 12
  • 14