Why a non-final “local” variable cannot be used inside an inner class, and instead a non-final field of the enclosing class can?

前端 未结 4 1784
囚心锁ツ
囚心锁ツ 2020-11-30 20:36

There are some topics on Stack Overflow on the compiler error Cannot refer to a non-final variable message inside an inner class defined in a different method a

相关标签:
4条回答
  • 2020-11-30 21:12

    The difference is between local (method) variables vs class member variables. A member variable exists during the lifetime of the enclosing object, so it can be referenced by the inner class instance. A local variable, however, exists only during the method invocation, and is handled differently by the compiler, in that an implicit copy of it is generated as the member of the inner class. Without declaring the local variable final, one could change it, leading to subtle errors due to the inner class still referring to the original value of that variable.

    Update: The Java Specialists' Newsletter #25 discusses this in more detail.

    Even the compiler error is misleading to me. Cannot refer to a non-final variable message inside an inner class defined in a different method: Different from what?

    From the inner class' run method I believe.

    0 讨论(0)
  • 2020-11-30 21:12

    The value you use must be final, but the non-final fields of a final reference can be changed. Note: this is implicitly a final reference. You cannot change it.

    private String enclosingClassField;
    private void updateStatus() {
        final MutableClass ms = new MutableClass(1, 2);
        Runnable doUpdateStatus = new Runnable() {
             public void run() {
                 // you can use `EnclosingClass.this` because its is always final
                 EnclosingClass.this.enclosingClassField = "";
                 // shorthand for the previous line.
                 enclosingClassField = "";
                 // you cannot change `ms`, but you can change its mutable fields.
                 ms.x = 3;
             }
        }
        /* do something with doUpdateStatus, like SwingUtilities.invokeLater() */
    }
    
    0 讨论(0)
  • 2020-11-30 21:24

    three types of things: instance variables, local variables,and objects:

    ■ Instance variables and objects live on the heap.
    ■ Local variables live on the stack.
    

    Inner class object cannot use the local variables of the method in which the local inner class is defined.

    because use local variables of the method is the local variables of the method are kept on the stack and lost as soon as the method ends.

    But even after the method ends, the local inner class object may still be alive on the heap. Method local inner class can still use the local variables that are marked final.

    final variable JVM takes these as a constant as they will not change after initiated . And when a inner class try to access them compiler create a copy of that variable into the heap and create a synthetic field inside the inner class so even when the method execution is over it is accessible because the inner class has it own copy.

    synthetic field are filed which actually doesn't exist in the source code but compiler create those fields in some inner classes to make those field accessible.

    0 讨论(0)
  • 2020-11-30 21:34

    The reason is that Java doesn't support closures. There are no JVM commands to access local variable from outside the method, whereas fields of class can be easily accessed from any place.

    So, when you use final local variable in an inner class, compiler actually passes a value of that variable into constructor of the inner class. Obviously, it won't work for non-final variables, since they value can change after construction of the inner class.

    Fields of containing class don't have this problem, because compiler implicitly passes a reference to the containing class into the constructor of the inner class, thus you can access its fields in a normal way, as you access fields of any other class.

    0 讨论(0)
提交回复
热议问题