分享

为什么匿名内部类方法参数要使用final

 hh3755 2014-07-29

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 and the solution is "declare it as final and you're done", but with this theoretical question I would like to inspect what is the logical reason why this code cannot compile:

private void updateStatus(String message) {
    Runnable doUpdateStatus = new Runnable() {
         public void run() {
             /* do something with message */
         }
    }
    /* do something with doUpdateStatus, like SwingUtilities.invokeLater() */
}

(solution: declare message as final) whereas this one does:

private String enclosingClassField;
private void updateStatus() {
    Runnable doUpdateStatus = new Runnable() {
         public void run() {
             /* do something with enclosingClassField */
         }
    }
    /* do something with doUpdateStatus, like SwingUtilities.invokeLater() */
}

I'm really confused. enclosingClassField is not final, it can change every time many times, whereas the poor message argument of updateStatus can only change within its method body, and is instead blamed by the compiler ;)

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? Isn't message defined in the same method as the inner class? Isn't enclosingClassField instead defined outside the method? Uhm...

Can someone point me to the correct interpretation of this matter? Thanks.

share|improve this question
    
EDIT: humph I've just found this: /questions/1299837/… Sorry guys –  gd1 Apr 27 '11 at 9:32

3 Answers

up vote 12 down vote accepted

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.

share|improve this answer
3  
So Java could copy the value of the variable w/o bothering with this compiler error, but it instead forces you to declare the variable as final to tell you "hey, remember it gets copied into the inner class, so if you could change it afterwards, then you get a severe inconsistency. So you can't change it, and we're clear with that." –  gd1 Apr 27 '11 at 9:27
2  
@Giacomo, exactly. The designers attempted to minimize the number of ways developers can shoot themselves in the foot :-) This in turn may result in unintuitive (at first sight) behaviour by the compiler, but IMHO it is still much better than unintuitive behaviour from your running program. –  Péter T?r?k Apr 27 '11 at 9:30

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条评论

    发表

    请遵守用户 评论公约

    类似文章 更多