2

In the following example it works and compile by setting the parameter int i as final

class Miner1
{
    Miner getMiner(final int i) {
        return new Miner() {                
           public void perform_work() { 
              System.out.println(i);
           }
        };
    }

interface Miner { void perform_work(); }

Otherwise if not set to final as the preceding example it won't compile. Does anybody know why? It should be on scope even without final as the curly parenthesis are not yet closed.

Thanks in advance.

default locale
  • 13,035
  • 13
  • 56
  • 62
Rollerball
  • 12,618
  • 23
  • 92
  • 161

4 Answers4

4

This is not to do with scope it is do with the anonymous inner classes.

You cannot access a local variable from an anonymous class that is declared in the parent class unless that variable is final.

Take a look at this other question on SO that explains the logic.

Community
  • 1
  • 1
Boris the Spider
  • 59,842
  • 6
  • 106
  • 166
3

It doesn't have anything to do with scope.

In Java, an anonymous class can only refer to those variables from outside scopes that are final.

From the JLS:

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

NPE
  • 486,780
  • 108
  • 951
  • 1,012
2

Java allows only final variables/arguments to be referred from anonymous classes defined inside the method/constructor. This is to make behavior of the code more intuitive. The value of variable/argument is passed to instance of anonymous class via hidden constructor argument at a time the instance is created, so instance of anonymous class cannot track further changes of the variable. If access to non-final variables would be allowed, one may write the following:

int a = 5;

Thread t = new Thread ()
{
    @Override
    public void run ()
    {
        System.out.println (a); // This will print 5, rather than 6!
    }
};

a = 6;

t.start ();

And expect 6 to be printed. To understand, why the code above will print 5, note that this code is equivalent to the following:

class MyThread extends Thread
{
    int _a;

    public MyThread (int a)
    {
        this._a = a;
    }

    @Override
    public void run ()
    {
        System.out.println (_a);
    }
}

int a = 5;

Thread t = new MyThread (a); // Value `5` is passed

a = 6;

t.start (); // Value `5` passed to the constructor earlier is printed here
Mikhail Vladimirov
  • 13,572
  • 1
  • 38
  • 40
0

This is because , in Java, anonymous inner class can access only final local variables and the fields of class.
Now the question is WHY?
It is because the local variables of the method (getMiner in your case) live on the stack, and exists only for the lifetime of the method. The scope of local variable is limited to the enclosed method the variable is declared in. When the method ends, the stack frame is blown a way and the variable is history. But even after the method completes, the inner class object created within it might still be alive on heap. And if for example a reference of anonymous inner class Miner obtained via getMiner is passed to some other location of code and used over there then since the local variables are already blown up it would be a bizarre situation for that object. One solution of this problem could be that the anonymous inner class object make a copy of local variable. But again it won't guarantee that the anonymous inner class object will see the latest value for that variable because, the local variables are susceptible to changes.

But if the local variable is final, it ensures that the variable value will not change at any condition after being initiallized so, the method-local inner class can just make a copy of it for private use, which will exist even after the original values has been removed from the stack.

Vishal K
  • 12,976
  • 2
  • 27
  • 38