2

Why I cannot refer to a non-final variable inside an inner class defined in a different method?
I've seen topics about this and in most of them people say that your component should be final and ... . But nobody says why?!! and I don't know what's the philosophy behind this limitation.
What makes me confused more is that the following code is erroneous :

JButton removeJBtn = new JButton("Remove");
    JButton addJBtn = new JButton("Add");
    //...
    btnNewButton.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
            removeJBtn.disable();//Error here,Cannot ...


        }
    });

while if I define

 JButton removeJBtn

as a member field (in the body of the class,not the method) it's not required to be defined as final!


I'll really appreciate any logical answer to this daily limit that I (and probably many others) always face.


Dear users that marked this question as a duplicate, please at least give a reference to the original question (that has been answered for sure!), there is a link in added above my question that I read it throughly but it's full of contradictions, some one (with 88 up votes) says java captures the value of final variables and it's completely rejected by a comment (with 16 votes) below it.

Mohsen Kamrani
  • 7,177
  • 5
  • 42
  • 66
  • 2
    see why [here](http://stackoverflow.com/questions/1299837/cannot-refer-to-a-non-final-variable-inside-an-inner-class-defined-in-a-differen) – Salah Feb 27 '14 at 08:51
  • Note: Inner classes and anonymous classes are a totally different thing! – Smutje Feb 27 '14 at 08:55
  • @Smutje: Would you please explain more? – Mohsen Kamrani Feb 27 '14 at 09:00
  • 1
    Okay, should have taken more time: Anonymous classes are a special kind of inner class. For more information, see http://docs.oracle.com/javase/tutorial/java/javaOO/nested.html – Smutje Feb 27 '14 at 09:05

3 Answers3

9

The local variables of the method live on the stack, and exist only for the lifetime of the method. You already know that the scope of a local variable is limited to the method the variable is declared in. When the method ends, the stack frame is blown away and the variable is history. But even after the method completes, the inner class object created within it might still be alive on the heap if, for example, a reference to it was passed into some other code and then stored in an instance variable. Because the local variables aren't guaranteed to be alive as long as the method-local inner class object, the inner class object can't use them. Unless the local variables are marked final!

Source: Kathy Sierra SCJP

Touchstone
  • 5,575
  • 7
  • 41
  • 48
  • So do you say the inner class (ActionListener here) may remains alive whilst removeJBtn has been destroyed? does marking it as final keeps it alive? – Mohsen Kamrani Feb 27 '14 at 08:58
  • This isn't quite right. See the comment thread on the accepted answer here: http://stackoverflow.com/questions/1299837/cannot-refer-to-a-non-final-variable-inside-an-inner-class-defined-in-a-differen. Also, there's a good discussion of variable capture by value here: http://en.wikipedia.org/wiki/Closure_(computer_programming)#Local_classes_.28Java.29. – Turix Feb 27 '14 at 09:37
1

Because a normal variable only resides on the stack (the pointer to the object in your case). Since the inner class can (and usually does) live longer than the defining method, the variable would not be present anymore.

By making the variable final, the compiler can create optimizations (in this case: include the final variable as "secret" member in the inner class. This would not be valid, if the variable were not final, because it could change afterwards.

blackbuild
  • 5,026
  • 1
  • 23
  • 35
1

Extending the other answers, you should keep in mind that anonymous classes are syntactic Java sugar to keep you from creating concrete classes and instantiating them every time you for example have to provide a button listener - if you want to do this (you can easily skip anonymous classes and replace them by concrete classes without a problem), you had to pass the values (here: the removeJBtn) into the objects by constructor to use them internally and you had created a new object explicitly, which lives on the heap and therefore longer then the method where you register the listeners.

Smutje
  • 17,733
  • 4
  • 24
  • 41