用java final关键字作弊

时间:2016-04-21 09:11:33

标签: java asynchronous scope static final

我正在写一些java代码,有一刻我被阻止了一件事。

final String action = "action1";
final Button otherAction = (findById....);
otherAction.setOnClickListener(new View.OnClickListener() {
    @Override
        public void onClick(View v) {
            if (action.equals("action1")) {
                action = "action2";
            } else if (action.equals("action2")) {
                action = "action3";
            } else if (action.equals("action3")) {
                action = "action1";
            }
        }
    });

显然这段代码不起作用,因为我无法为action分配新值,因为它是最终变量,所以只能初始化一次。
要从onClickListener范围内访问变量,必须将其声明为final。

所以我采取的措施是:

final Button otherAction = (findById....);
otherAction.setOnClickListener(new View.OnClickListener() {
    @Override
        public void onClick(View v) {
            if (t.action.equals("action1")) {
                t.action = "action2";
            } else if (t.action.equals("action2")) {
                t.action = "action3";
            } else if (t.action.equals("action3")) {
                t.action = "action1";
            }
        }
    });

Class t {
    public static String action = "action1";
}

我的问题是:为什么这有效?

2 个答案:

答案 0 :(得分:3)

字段不一定要从匿名类访问,只需要方法变量。

这是因为字段(其实体或类)存在,直到不再需要它(由GC确定),所以总有一个地方可以分配。

但是,如果您在某处传递匿名类实例,则在包含方法已退出时它可能仍然存在。想象一下,otherAction在遥远的未来调用这个监听器sowetime。但是无处可再分配这个变量,因此它应该是最终的并且可以在任何类实例化中复制。

答案 1 :(得分:0)

据我所知,第一个代码块不起作用。这里的“工作”意味着:编译错误。

第二个是有效的,因为如果遵循Java语言规范。非局部参数,形式参数没有限制.t.action是一个静态变量。

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

Any local variable used but not declared in an inner class must be definitely assigned (§16) before the body of the inner class.

http://docs.oracle.com/javase/specs/jls/se7/html/jls-8.html#jls-8.1.3

另一个注意事项是Java 8之前的版本.Java 8引入了以下概念:有效的final,用于内部类的局部变量不需要正式声明为final。有关更多详细信息,请参阅: https://docs.oracle.com/javase/specs/jls/se8/html/jls-8.html#jls-8.1.3

Any local variable, formal parameter, or exception parameter used but not declared in an inner class must either be declared final or be **effectively** final (§4.12.4), or a compile-time error occurs where the use is attempted.

在此处查看有关有效决赛的更多解释: Difference between final and effectively final

关于第二个代码块的工作原理,您可以在这里阅读: Why are only final variables accessible in anonymous class?

它提供了我见过的这个问题的最合理的答案:)