4

I grew up knowing that final is a keyword that when applied to variables does not make it possible to reassign the variable to something else. "If a variable is final then it's a constant" summarize many and while I'm not a fan of that definition it's probably a good way to keep the concept in mind. I just prefer to say that you cannot change the value of the variable (whatever "the value" means).

My life was happy but one day I took a deeper look at method local inner classes...

An inner class defined inside a method cannot access variables defined in the method itself. Why? Because while the class lives in the Heap and it might keep existing after the method completes (a valid reference of the class might be passed and stored somewhere else), those variables live in the stack and they die when the method returns. We don't want to have an inner class trying to access a variable that does not exist anymore at a later time because then the world will end.

Perfect. It makes sense. Excellent! And then: unless you declare those variables final..... Then your class can access them and the compiler doesn't send you to hell...

WHY??? I mean, what kind of sorcery is this? What does final exactly do and why I had to wait to talk about method local inner classes to figure this out? Assuming the final variables are stored in the Heap no matter where they are defined, are there any other applications besides the concept of making method local inner classes happy?

Marsellus Wallace
  • 17,991
  • 25
  • 90
  • 154
  • http://stackoverflow.com/questions/1299837/cannot-refer-to-a-non-final-variable-inside-an-inner-class-defined-in-a-differen – assylias May 25 '12 at 14:36
  • 2
    Have you read **Where are java final local variables stored**: http://stackoverflow.com/questions/1945663/where-are-java-final-local-variables-stored – Mesop May 25 '12 at 14:41

5 Answers5

6

Quoted from "The Final word on the final keyword":

The reason for this restriction [Local classes can only reference local variables and parameters that are declared final.] becomes apparent if we shed some light on how local classes are implemented. An anonymous local class can use local variables because the compiler automatically gives the class a private instance field to hold a copy of each local variable the class uses. The compiler also adds hidden parameters to each constructor to initialize these automatically created private fields. Thus, a local class does not actually access local variables, but merely its own private copies of them. The only way this can work correctly is if the local variables are declared final, so that they are guaranteed not to change. With this guarantee in place, the local class is assured that its internal copies of the variables accurately reflect the actual local variables.

pgras
  • 12,614
  • 4
  • 38
  • 46
4

In the situation you are referring to, you can potentially get into a weird situation. When you create an inner class in a method, the scope of that inner class can live past the lifetime of the method invocation. So, if you allow the inner class to refer to a variable which is only defined within the method itself, what happens when the method completes?

for example:

public void doSomethingLater()
{
  int value = 13;

  Thread t = new Thread(new Runnable() { 
    @Override public void run() {
      System.out.println("The value is " + value);
    }
  });
  t.start();

  value = 25;
}

Assume that was allowable java code. What would that program print when run? 13? 25? In order to implement inner class access to method local variables, the Java designers decided to take the simple route of copying the value of the variable at inner class creation time. to make it abundantly clear to the Java programmer that the value was copied, they force you to use final references so that your method cannot modify that variable at a future point in time (which might confuse the developer who expects that the new value would affect the inner class).

In reality, this is what happens under the hood:

public void doSomethingLater()
{
  int value = 13;

  Thread t = new Thread(new Runnable() { 
    private final _innerValue = value;
    @Override public void run() {
      System.out.println("The value is " + _innerValue);
    }
  });
  t.start();

  value = 25;
}

thus, you can see that the later modification to value will not affect the inner class.

UPDATE:

well, guess @pgras beat me to it. anyway, this is an example of the quote included in that answer.

jtahlborn
  • 52,909
  • 5
  • 76
  • 118
1

In Java, final does literally mean "if a variable is final it's a constant", but that doesn't mean what a lot of people think it means.

With primitives it really does mean that. But with objects, all final means is that you cannot change which object instance the variable refers to. However, you are fully allowed to change that object as much as you want.

And that's why method local inner classes need the variables it references to be declared final. Their being declared final guarantees that the method cannot change which objects those variables refer to, a guarantee that is needed for the method inner class to function properly.

And you're confusing variables and objects when you're talking about heap and stack. The method-local variables that refer to objects live on the stack but the objects they refer to live on the heap. So the inner class can continue to refer to those objects even when the method goes out of scope, since the objects instance exist outside of the scope of the method.

QuantumMechanic
  • 13,795
  • 4
  • 45
  • 66
0

Actually, it's a duplicate of: Cannot refer to a non-final variable inside an inner class defined in a different method

See this answer: https://stackoverflow.com/a/1299889/277683

You seem to understand the stack etc., so I'll be brief. To sum up, when you make a reference final, the compiler can safely determine its value at compile time and use the same thing for the inner class.

Community
  • 1
  • 1
Konrad Garus
  • 53,145
  • 43
  • 157
  • 230
0

The answer is far more simple.

The Java developers(The guys who made java) thought it would be confusing if you could access a variable which were not final in an inner class, so they added a requirement that the variable should be final to avoid confusion.

I am not sure exactly how java implements this, but I guess they simply copy the variable when the inner class is created. Something which could easily be done with non final variables as well, but which the java developers thought would be confusing.

MTilsted
  • 5,425
  • 9
  • 44
  • 76